Selaa lähdekoodia

Initial code commit

Bepis 6 vuotta sitten
vanhempi
commit
bbe9c64ef1
100 muutettua tiedostoa jossa 40387 lisäystä ja 0 poistoa
  1. 63 0
      .gitattributes
  2. 261 0
      .gitignore
  3. 25 0
      NTERA.sln
  4. 6 0
      NTERA/App.config
  5. 75 0
      NTERA/Console/ConsoleControl.Designer.cs
  6. 90 0
      NTERA/Console/ConsoleControl.cs
  7. 120 0
      NTERA/Console/ConsoleControl.resx
  8. 85 0
      NTERA/Console/ConsoleRenderer.cs
  9. 17 0
      NTERA/Console/DoubleBufferedPanel.cs
  10. 329 0
      NTERA/Console/EraConsoleInstance.cs
  11. 47 0
      NTERA/Console/HTMLParser.cs
  12. 12 0
      NTERA/Console/IRenderItem.cs
  13. 13 0
      NTERA/Console/RenderItem/BaseRenderItem.cs
  14. 46 0
      NTERA/Console/RenderItem/ButtonTextRenderItem.cs
  15. 60 0
      NTERA/Console/RenderItem/ImageRenderItem.cs
  16. 37 0
      NTERA/Console/RenderItem/TextRenderItem.cs
  17. 615 0
      NTERA/Game/Config/Config.cs
  18. 170 0
      NTERA/Game/Config/ConfigCode.cs
  19. 660 0
      NTERA/Game/Config/ConfigData.cs
  20. 295 0
      NTERA/Game/Config/ConfigItem.cs
  21. 129 0
      NTERA/Game/Config/KeyMacro.cs
  22. 19 0
      NTERA/Game/Content/AContentFile.cs
  23. 9 0
      NTERA/Game/Content/AContentItem.cs
  24. 122 0
      NTERA/Game/Content/AppContents.cs
  25. 56 0
      NTERA/Game/Content/BaseImage.cs
  26. 21 0
      NTERA/Game/Content/CroppedImage.cs
  27. 43 0
      NTERA/Game/Display/AConsoleDisplayPart.cs
  28. 266 0
      NTERA/Game/Display/ButtonStringCreator.cs
  29. 240 0
      NTERA/Game/Display/ConsoleButtonString.cs
  30. 145 0
      NTERA/Game/Display/ConsoleDisplayLine.cs
  31. 163 0
      NTERA/Game/Display/ConsoleImagePart.cs
  32. 187 0
      NTERA/Game/Display/ConsoleShapePart.cs
  33. 97 0
      NTERA/Game/Display/ConsoleStyledString.cs
  34. 1050 0
      NTERA/Game/Display/HTMLManager.cs
  35. 543 0
      NTERA/Game/Display/PrintStringBuffer.cs
  36. 87 0
      NTERA/Game/Display/StringMeasure.cs
  37. 1446 0
      NTERA/Game/GameData/ConstantData.cs
  38. 26 0
      NTERA/Game/GameData/DefineMacro.cs
  39. 78 0
      NTERA/Game/GameData/Expression/CaseExpression.cs
  40. 144 0
      NTERA/Game/GameData/Expression/ExpressionMediator.cs
  41. 623 0
      NTERA/Game/GameData/Expression/ExpressionParser.cs
  42. 44 0
      NTERA/Game/GameData/Expression/IOperandTerm.cs
  43. 130 0
      NTERA/Game/GameData/Expression/OperatorCode.cs
  44. 824 0
      NTERA/Game/GameData/Expression/OperatorMethod.cs
  45. 132 0
      NTERA/Game/GameData/Expression/Term.cs
  46. 2693 0
      NTERA/Game/GameData/Function/Creator.Method.cs
  47. 154 0
      NTERA/Game/GameData/Function/Creator.cs
  48. 55 0
      NTERA/Game/GameData/Function/FunctionMethod.cs
  49. 56 0
      NTERA/Game/GameData/Function/FunctionMethodTerm.cs
  50. 293 0
      NTERA/Game/GameData/Function/TRCommands.cs
  51. 155 0
      NTERA/Game/GameData/Function/UserDefinedMethodTerm.cs
  52. 89 0
      NTERA/Game/GameData/Function/UserDefinedRefMethod.cs
  53. 182 0
      NTERA/Game/GameData/GameBase.cs
  54. 672 0
      NTERA/Game/GameData/IdentifierDictionary.cs
  55. 173 0
      NTERA/Game/GameData/ParserMediator.cs
  56. 297 0
      NTERA/Game/GameData/StrForm.cs
  57. 769 0
      NTERA/Game/GameData/Variable/CharacterData.cs
  58. 532 0
      NTERA/Game/GameData/Variable/Translation.cs
  59. 284 0
      NTERA/Game/GameData/Variable/VariableCode.cs
  60. 1111 0
      NTERA/Game/GameData/Variable/VariableData.cs
  61. 2442 0
      NTERA/Game/GameData/Variable/VariableEvaluator.cs
  62. 245 0
      NTERA/Game/GameData/Variable/VariableIdentifier.cs
  63. 108 0
      NTERA/Game/GameData/Variable/VariableLocal.cs
  64. 197 0
      NTERA/Game/GameData/Variable/VariableParser.cs
  65. 56 0
      NTERA/Game/GameData/Variable/VariableStrArgTerm.cs
  66. 441 0
      NTERA/Game/GameData/Variable/VariableTerm.cs
  67. 2956 0
      NTERA/Game/GameData/Variable/VariableToken.cs
  68. 1445 0
      NTERA/Game/GameProc/ErbLoader.cs
  69. 526 0
      NTERA/Game/GameProc/Function/Argument.cs
  70. 1888 0
      NTERA/Game/GameProc/Function/ArgumentBuilder.cs
  71. 57 0
      NTERA/Game/GameProc/Function/ArgumentParser.cs
  72. 360 0
      NTERA/Game/GameProc/Function/BuiltInFunctionCode.cs
  73. 158 0
      NTERA/Game/GameProc/Function/CircularBuffer.cs
  74. 235 0
      NTERA/Game/GameProc/Function/Clipboard.cs
  75. 79 0
      NTERA/Game/GameProc/Function/FunctionArgType.cs
  76. 575 0
      NTERA/Game/GameProc/Function/FunctionIdentifier.cs
  77. 2380 0
      NTERA/Game/GameProc/Function/Instraction.Child.cs
  78. 24 0
      NTERA/Game/GameProc/Function/Instruction.cs
  79. 253 0
      NTERA/Game/GameProc/HeaderFileLoader.cs
  80. 42 0
      NTERA/Game/GameProc/InputRequest.cs
  81. 260 0
      NTERA/Game/GameProc/LabelDictionary.cs
  82. 343 0
      NTERA/Game/GameProc/LogicalLine.cs
  83. 488 0
      NTERA/Game/GameProc/LogicalLineParser.cs
  84. 312 0
      NTERA/Game/GameProc/Process.CalledFunction.cs
  85. 946 0
      NTERA/Game/GameProc/Process.ScriptProc.cs
  86. 531 0
      NTERA/Game/GameProc/Process.State.cs
  87. 1015 0
      NTERA/Game/GameProc/Process.SystemProc.cs
  88. 487 0
      NTERA/Game/GameProc/Process.cs
  89. 190 0
      NTERA/Game/GameProc/UserDefinedFunction.cs
  90. 313 0
      NTERA/Game/GameProc/UserDefinedVariable.cs
  91. 56 0
      NTERA/Game/GlobalStatic.cs
  92. 133 0
      NTERA/Game/Sub/EmueraException.cs
  93. 727 0
      NTERA/Game/Sub/EraBinaryDataReader.cs
  94. 421 0
      NTERA/Game/Sub/EraBinaryDataWriter.cs
  95. 754 0
      NTERA/Game/Sub/EraDataStream.cs
  96. 167 0
      NTERA/Game/Sub/EraStreamReader.cs
  97. 1260 0
      NTERA/Game/Sub/LexicalAnalyzer.cs
  98. 156 0
      NTERA/Game/Sub/StringStream.cs
  99. 58 0
      NTERA/Game/Sub/SubWord.cs
  100. 138 0
      NTERA/Game/Sub/Word.cs

+ 63 - 0
.gitattributes

@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs     diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following 
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln       merge=binary
+#*.csproj    merge=binary
+#*.vbproj    merge=binary
+#*.vcxproj   merge=binary
+#*.vcproj    merge=binary
+#*.dbproj    merge=binary
+#*.fsproj    merge=binary
+#*.lsproj    merge=binary
+#*.wixproj   merge=binary
+#*.modelproj merge=binary
+#*.sqlproj   merge=binary
+#*.wwaproj   merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg   binary
+#*.png   binary
+#*.gif   binary
+
+###############################################################################
+# diff behavior for common document formats
+# 
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the 
+# entries below.
+###############################################################################
+#*.doc   diff=astextplain
+#*.DOC   diff=astextplain
+#*.docx  diff=astextplain
+#*.DOCX  diff=astextplain
+#*.dot   diff=astextplain
+#*.DOT   diff=astextplain
+#*.pdf   diff=astextplain
+#*.PDF   diff=astextplain
+#*.rtf   diff=astextplain
+#*.RTF   diff=astextplain

+ 261 - 0
.gitignore

@@ -0,0 +1,261 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# DNX
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+#*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/packages/repositories.config
+# NuGet v3's project.json files produces more ignoreable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+node_modules/
+orleans.codegen.cs
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# CodeRush
+.cr/
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc

+ 25 - 0
NTERA.sln

@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27703.2042
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NTERA", "NTERA\NTERA.csproj", "{FE5FA346-E06B-43FA-80D2-73C529ADF48A}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{FE5FA346-E06B-43FA-80D2-73C529ADF48A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{FE5FA346-E06B-43FA-80D2-73C529ADF48A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{FE5FA346-E06B-43FA-80D2-73C529ADF48A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{FE5FA346-E06B-43FA-80D2-73C529ADF48A}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {08F1D450-D45E-4649-A546-259F0AEEA4E2}
+	EndGlobalSection
+EndGlobal

+ 6 - 0
NTERA/App.config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/>
+    </startup>
+</configuration>

+ 75 - 0
NTERA/Console/ConsoleControl.Designer.cs

@@ -0,0 +1,75 @@
+namespace NTERA.Console
+{
+	partial class ConsoleControl
+	{
+		/// <summary> 
+		/// Required designer variable.
+		/// </summary>
+		private System.ComponentModel.IContainer components = null;
+
+		/// <summary> 
+		/// Clean up any resources being used.
+		/// </summary>
+		/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+		protected override void Dispose(bool disposing)
+		{
+			if (disposing && (components != null))
+			{
+				components.Dispose();
+			}
+			base.Dispose(disposing);
+		}
+
+		#region Component Designer generated code
+
+		/// <summary> 
+		/// Required method for Designer support - do not modify 
+		/// the contents of this method with the code editor.
+		/// </summary>
+		private void InitializeComponent()
+		{
+			this.offsetScrollBar = new System.Windows.Forms.VScrollBar();
+			this.displayPanel = new DoubleBufferedPanel();
+			this.SuspendLayout();
+			// 
+			// offsetScrollBar
+			// 
+			this.offsetScrollBar.Dock = System.Windows.Forms.DockStyle.Right;
+			this.offsetScrollBar.Location = new System.Drawing.Point(327, 0);
+			this.offsetScrollBar.Name = "offsetScrollBar";
+			this.offsetScrollBar.Size = new System.Drawing.Size(17, 246);
+			this.offsetScrollBar.TabIndex = 0;
+			this.offsetScrollBar.Value = 100;
+			this.offsetScrollBar.Scroll += new System.Windows.Forms.ScrollEventHandler(this.offsetScrollBar_Scroll);
+			// 
+			// displayPanel
+			// 
+			this.displayPanel.Dock = System.Windows.Forms.DockStyle.Fill;
+			this.displayPanel.Location = new System.Drawing.Point(0, 0);
+			this.displayPanel.Name = "displayPanel";
+			this.displayPanel.Size = new System.Drawing.Size(327, 246);
+			this.displayPanel.TabIndex = 1;
+			this.displayPanel.Paint += new System.Windows.Forms.PaintEventHandler(this.displayPanel_Paint);
+			this.displayPanel.MouseMove += new System.Windows.Forms.MouseEventHandler(this.displayPanel_MouseMove);
+			this.displayPanel.Resize += new System.EventHandler(this.displayPanel_Resize);
+			// 
+			// ConsoleControl
+			// 
+			this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+			this.BackColor = System.Drawing.Color.Black;
+			this.Controls.Add(this.displayPanel);
+			this.Controls.Add(this.offsetScrollBar);
+			this.DoubleBuffered = true;
+			this.Name = "ConsoleControl";
+			this.Size = new System.Drawing.Size(344, 246);
+			this.ResumeLayout(false);
+
+		}
+
+		#endregion
+
+		private System.Windows.Forms.VScrollBar offsetScrollBar;
+		private DoubleBufferedPanel displayPanel;
+	}
+}

+ 90 - 0
NTERA/Console/ConsoleControl.cs

@@ -0,0 +1,90 @@
+using System;
+using System.Windows.Forms;
+
+namespace NTERA.Console
+{
+	public partial class ConsoleControl : UserControl
+	{
+		public readonly ConsoleRenderer Renderer = new ConsoleRenderer();
+		
+		public ConsoleControl()
+		{
+			InitializeComponent();
+
+	//		Renderer.Items.Add(new TextRenderItem("Sia - Chandelier (Alternative♂Version)"));
+	//		Renderer.Items.Add(new TextRenderItem("【本格的LatinPop】Livin' la Mara Loca - 嗶哩嗶哩 - ( ゜- ゜)つロ 乾杯~."));
+	//		Renderer.Items.Add(new ButtonTextRenderItem("-- fisting is $300", new[] { new CharacterRange(3, 7) }));
+	//		Renderer.Items.AddRange(ImageRenderItem.CreateFromLargeBitmap(new Bitmap(@"B:\we gotta find the princess.PNG"), Renderer.LineHeight));
+	//		Renderer.Items.AddRange(TextRenderItem.CreateFromLinedText(@"Dear Pesky Plumbers,
+	//The Koopalings and I have taken over the Mushroom Kingdom.
+	//The Princess is now a permanent guest at one of my seven Koopa Hotels.
+	//I dare you to find her, if you can!
+	//- Bowser"));
+			
+			displayPanel.MouseWheel += (sender, args) => //this adds scrolling capability to the panel, so you can scroll on it
+			{
+				int oldValue = offsetScrollBar.Value;
+				int trueMaximum = Math.Max(1, (1 + offsetScrollBar.Maximum) - offsetScrollBar.LargeChange);
+
+				offsetScrollBar.Value = Math.Min(offsetScrollBar.Maximum - 1, Math.Max(0, Math.Min(offsetScrollBar.Value, trueMaximum) + (offsetScrollBar.SmallChange * args.Delta / -120)));
+				
+				offsetScrollBar_Scroll(null, new ScrollEventArgs(ScrollEventType.SmallDecrement, oldValue, offsetScrollBar.Value));
+			};
+
+			Renderer.AddedItem += (item) =>
+			{
+				if (InvokeRequired)
+				{
+					Invoke(new MethodInvoker(() => Invalidate(true)));
+				}
+				else
+				{
+					Invalidate(true);
+				}
+			};
+		}
+
+		protected override void OnResize(EventArgs e)
+		{
+			base.OnResize(e);
+
+			Invalidate(ClientRectangle, true);
+		}
+
+		private void displayPanel_Paint(object sender, PaintEventArgs e)
+		{
+			int lineCount = Renderer.Render(e.Graphics, displayPanel.ClientRectangle, displayPanel.ClientRectangle, PointToClient(MousePosition)); //this is the only code in this method related to rendering. everything else is because MS fucked up what ScrollBar.Maximum actually is
+		}
+
+		private void displayPanel_MouseMove(object sender, MouseEventArgs e)
+		{
+			Renderer.MouseHoverEvent(e.Location, this);
+		}
+
+		private void displayPanel_Resize(object sender, EventArgs e)
+		{
+			base.OnResize(e);
+
+			Invalidate();
+		}
+		
+		private void offsetScrollBar_Scroll(object sender, ScrollEventArgs e)
+		{
+			if (e.NewValue != e.OldValue)
+			{
+				int trueMaximum = Math.Max(1, (1 + offsetScrollBar.Maximum) - offsetScrollBar.LargeChange);
+
+				int newOffset = Math.Max(0, trueMaximum - offsetScrollBar.Value);
+
+				if (newOffset == Renderer.offset)
+					return;
+
+				Renderer.offset = newOffset;
+
+				Invalidate(ClientRectangle, true);
+
+				offsetScrollBar.Maximum = (Renderer.LastLineCount - 1) + offsetScrollBar.LargeChange;
+			}
+		}
+	}
+}

+ 120 - 0
NTERA/Console/ConsoleControl.resx

@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 85 - 0
NTERA/Console/ConsoleRenderer.cs

@@ -0,0 +1,85 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace NTERA.Console
+{
+	public class ConsoleRenderer
+	{
+		public int LineHeight = 16;
+
+		public List<IRenderItem> Items { get; protected set; } = new List<IRenderItem>();
+		
+		public int offset;
+
+		public int LastLineCount;
+
+		public delegate void AddedItemEventHandler(IRenderItem item);
+		public event AddedItemEventHandler AddedItem;
+
+		public void AddItem(IRenderItem item)
+		{
+			Items.Add(item);
+
+			AddedItem?.Invoke(item);
+		}
+
+		public int Render(Graphics graphics, Rectangle clientArea, Rectangle invalidateArea, Point mousePointer)
+		{
+			int lastItem = Items.Count - offset;
+
+			int screenLineCount = (int)Math.Ceiling(clientArea.Height / (float)LineHeight);
+
+			int firstItem = Math.Max(0, lastItem - screenLineCount);
+
+			for (int i = firstItem; i < lastItem; i++)
+			{
+				int y = clientArea.Height - (lastItem - i) * LineHeight;
+
+				var itemArea = new Rectangle(0, y, clientArea.Width, LineHeight);
+
+				if (!invalidateArea.IntersectsWith(itemArea))
+					continue;
+
+				itemArea.Intersect(invalidateArea);
+				itemArea.Y -= LineHeight - itemArea.Height;
+				itemArea.Height = LineHeight;
+
+				Items[i].Render(graphics, itemArea, mousePointer);
+			}
+
+			LastLineCount = screenLineCount;
+			return screenLineCount;
+		}
+
+
+		protected RectangleF? lastUpdateRange = null;
+
+		public void MouseHoverEvent(Point mousePoint, Control control)
+		{
+			foreach (var item in Items)
+			{
+				foreach (var rect in item.UpdateRegions)
+				{
+					if (!rect.Contains(mousePoint))
+						continue;
+
+					if (rect != lastUpdateRange)
+					{
+						control.Invalidate(Rectangle.Round(rect), true);
+						lastUpdateRange = rect;
+					}
+							
+					return;
+				}
+			}
+
+			if (lastUpdateRange != null)
+			{
+				control.Invalidate(Rectangle.Round(lastUpdateRange.Value), true);
+				lastUpdateRange = null;
+			}
+		}
+	}
+}

+ 17 - 0
NTERA/Console/DoubleBufferedPanel.cs

@@ -0,0 +1,17 @@
+using System.Windows.Forms;
+
+namespace NTERA.Console
+{
+	class DoubleBufferedPanel : Panel
+	{
+		public DoubleBufferedPanel()
+		{
+			DoubleBuffered = true;
+			SetStyle(ControlStyles.Opaque, true);
+			SetStyle(ControlStyles.UserPaint, true);
+			SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
+			SetStyle(ControlStyles.AllPaintingInWmPaint, true);
+			//SetStyle(ControlStyles.ResizeRedraw, true);
+		}
+	}
+}

+ 329 - 0
NTERA/Console/EraConsoleInstance.cs

@@ -0,0 +1,329 @@
+using System.Drawing;
+using System.Text;
+using System.Threading;
+using MinorShift.Emuera.GameProc;
+using MinorShift.Emuera.Sub;
+using NTERA.Game.Display;
+using NTERA.Interop;
+
+namespace NTERA.Console
+{
+	public class EraConsoleInstance : IConsole
+	{
+		public ConsoleRenderer Renderer { get; }
+
+		public AutoResetEvent InputResetEvent { get; protected set; } = new AutoResetEvent(false);
+
+		public void AddText(string text)
+		{
+			Renderer.AddItem(new TextRenderItem(text));
+		}
+
+		public void AddText(string text, Color color)
+		{
+			var item = new TextRenderItem(text);
+			item.TextBrush = new SolidBrush(color);
+
+			Renderer.AddItem(item);
+		}
+
+
+		public bool IsRunning { get; set; } = true;
+		public bool Enabled { get; set; } = true;
+
+
+
+		public EraConsoleInstance(ConsoleRenderer renderer)
+		{
+			Renderer = renderer;
+		}
+
+		public InputRequest CurrentRequest { get; set; }
+
+		public void GiveInput(string input)
+		{
+			PrintSingleLine(input);
+			InputResetEvent.Set();
+		}
+
+
+
+
+
+
+		public void PrintError(string message)
+		{
+			AddText(message, Color.Red);
+		}
+
+		public void PrintSystemLine(string message)
+		{
+			AddText(message, Color.Gray);
+		}
+
+		public void DebugClearTraceLog()
+		{
+		}
+
+		public void DebugAddTraceLog(string message)
+		{
+		}
+
+		public void DebugRemoveTraceLog()
+		{
+		}
+
+		public bool RunERBFromMemory { get; set; }
+		public void PrintWarning(string message, ScriptPosition position, int level)
+		{
+			AddText(message, Color.Yellow);
+		}
+
+		public void setStBar(string bar)
+		{
+		}
+
+		public void ReadAnyKey()
+		{
+			IsRunning = false;
+			Thread.Sleep(500);
+			IsRunning = true;
+		}
+
+		public void WaitInput(InputRequest request)
+		{
+			CurrentRequest = request;
+			IsRunning = false;
+
+			InputResetEvent.WaitOne();
+			CurrentRequest = null;
+			IsRunning = true;
+		}
+
+		public void ResetStyle()
+		{
+		}
+
+		public void OutputLog(string log)
+		{
+			AddText(log);
+		}
+
+		public bool noOutputLog { get; set; }
+		public void ThrowTitleError(bool something)
+		{
+		}
+
+		public void PrintBar()
+		{
+			printCustomBar("-");
+		}
+
+		public void PrintSingleLine(string line, bool something = false)
+		{
+			AddText(line);
+		}
+
+		public void RefreshStrings(bool something)
+		{
+		}
+
+		public void SetWindowTitle(string title)
+		{
+		}
+
+		public void ThrowError(bool playSound)
+		{
+		}
+
+		public void PrintErrorButton(string message, ScriptPosition position)
+		{
+		}
+
+		protected StringBuilder bodyBuilder = new StringBuilder();
+
+		public void Print(string message)
+		{
+			//message.Replace(' ', ' ');
+			bodyBuilder.Append(message);
+		}
+
+		public void NewLine()
+		{
+			AddText(bodyBuilder.ToString());
+			bodyBuilder.Length = 0;
+		}
+
+		public bool UseSetColorStyle { get; set; }
+		public void PrintC(string message, bool something)
+		{
+			AddText(message);
+		}
+
+		public DisplayLineAlignment Alignment { get; set; }
+		public void deleteLine(int line)
+		{
+		}
+
+		public void PrintTemporaryLine(string line)
+		{
+			AddText(line);
+		}
+
+		public bool updatedGeneration { get; set; }
+		public void PrintFlush(bool something)
+		{
+		}
+
+		public bool LastLineIsTemporary { get; set; }
+		public bool LastLineIsEmpty { get; set; }
+		public void ReloadErbFinished()
+		{
+		}
+
+		public bool MesSkip { get; set; }
+		public StringStyle StringStyle { get; set; }
+		public Color bgColor { get; set; }
+		public ConsoleRedraw Redraw { get; set; }
+		public bool EmptyLine { get; set; }
+		public string getStBar(string something)
+		{
+			return "";
+		}
+
+		public void PrintButton(string something, long something1)
+		{
+			Print(something);
+		}
+
+		public void PrintButton(string something, string something1)
+		{
+			Print(something);
+		}
+
+		public void PrintButtonC(string something, long something1, bool something2)
+		{
+			Print(something);
+		}
+
+		public void PrintButtonC(string something, string something1, bool something2)
+		{
+			Print(something);
+		}
+
+		public void PrintPlain(string message)
+		{
+			AddText(message);
+		}
+
+		public void printCustomBar(string bar)
+		{
+			AddText("".PadRight(300, bar[0]));
+		}
+
+		public bool UseUserStyle { get; set; }
+
+		public void Quit()
+		{
+		}
+
+		public void PrintHtml(string html, bool newline)
+		{
+			foreach (var item in HtmlParser.ParseHtml(html))
+				Renderer.AddItem(item);
+		}
+
+		public void PrintImg(string img)
+		{
+			AddText(img);
+		}
+
+		public void PrintShape(string shape, int[] param)
+		{
+			AddText(shape);
+		}
+
+		public void DebugPrint(string message)
+		{
+			AddText(message);
+		}
+
+		public void DebugNewLine()
+		{
+		}
+
+		public void DebugClear()
+		{
+		}
+
+		public void ReadAnyKey(bool something, bool something2)
+		{
+			Thread.Sleep(500);
+		}
+
+		public void SetStringStyle(Color color)
+		{
+		}
+
+		public void SetStringStyle(FontStyle fontStyle)
+		{
+		}
+
+		public void SetBgColor(Color color)
+		{
+		}
+
+		public void SetToolTipColor(Color fc, Color bc)
+		{
+		}
+
+		public void SetToolTipDelay(int delay)
+		{
+		}
+
+		public void SetToolTipDuration(int duration)
+		{
+		}
+
+		public void SetFont(string font)
+		{
+		}
+
+		public void SetRedraw(long value)
+		{
+		}
+
+		public int NewButtonGeneration { get; set; }
+		public void UpdateGeneration()
+		{
+		}
+
+		public bool ButtonIsSelected(ConsoleButtonString button)
+		{
+			return false;
+		}
+
+		public ConsoleDisplayLine[] GetDisplayLines(long something)
+		{
+			return new ConsoleDisplayLine[] { };
+		}
+
+		public ConsoleDisplayLine[] PopDisplayingLines()
+		{
+			return new ConsoleDisplayLine[] { };
+		}
+
+		public string GetWindowTitle()
+		{
+			return "title";
+		}
+
+		public long LineCount { get; set; }
+		public string getDefStBar()
+		{
+			return "";
+		}
+
+		public bool IsTimeOut { get; set; }
+	}
+}

+ 47 - 0
NTERA/Console/HTMLParser.cs

@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Xml.Linq;
+using MinorShift.Emuera.Content;
+using NTERA.Console;
+
+namespace NTERA.Interop
+{
+	public static class HtmlParser
+	{
+		public static IEnumerable<IRenderItem> ParseHtml(string html)
+		{
+			return ParseHtml_Internal(XElement.Parse(html));
+		}
+
+		private static IEnumerable<IRenderItem> ParseHtml_Internal(XElement xmlNode)
+		{
+			List<IRenderItem> renderItems = new List<IRenderItem>();
+
+			foreach (var node in xmlNode.Descendants())
+			{
+				switch (node.Name.LocalName)
+				{
+					case "p":
+						renderItems.AddRange(ParseHtml_Internal(node));
+						break;
+					case "img":
+						string src = node.Attribute("src")?.Value;
+
+						if (src == null)
+							throw new InvalidOperationException("HTML 'img' tag in script is missing 'src' attribute");
+
+						var image = AppContents.GetContent<CroppedImage>(src);
+
+						renderItems.Add(new ImageRenderItem(image.BaseImage.Bitmap, image.Rectangle));
+
+						break;
+					default:
+						renderItems.Add(new TextRenderItem(node.ToString()));
+						break;
+				}
+			}
+
+			return renderItems;
+		}
+	}
+}

+ 12 - 0
NTERA/Console/IRenderItem.cs

@@ -0,0 +1,12 @@
+using System;
+using System.Drawing;
+
+namespace NTERA.Console
+{
+	public interface IRenderItem : IDisposable
+	{
+		Rectangle[] UpdateRegions { get; }
+
+		void Render(Graphics graphics, Rectangle renderArea, Point mousePointer);
+	}
+}

+ 13 - 0
NTERA/Console/RenderItem/BaseRenderItem.cs

@@ -0,0 +1,13 @@
+using System.Drawing;
+
+namespace NTERA.Console
+{
+	public abstract class BaseRenderItem : IRenderItem
+	{
+		public Rectangle[] UpdateRegions { get; protected set; } = { };
+
+		public abstract void Render(Graphics graphics, Rectangle renderArea, Point mousePointer);
+
+		public virtual void Dispose() { }
+	}
+}

+ 46 - 0
NTERA/Console/RenderItem/ButtonTextRenderItem.cs

@@ -0,0 +1,46 @@
+using System.Drawing;
+using System.Linq;
+
+namespace NTERA.Console
+{
+	public class ButtonTextRenderItem : BaseRenderItem
+	{
+		public static Font Font { get; set; } = new Font("MS UI Gothic", 12); //new Font("Arial", 12);
+
+		public static SolidBrush TextBrush = new SolidBrush(Color.White);
+
+		public static SolidBrush BackingHighlightBrush = new SolidBrush(Color.DarkRed);
+
+		public static SolidBrush SelectedBackingHighlightBrush = new SolidBrush(Color.Yellow);
+
+		public string Text { get; set; }
+
+		public CharacterRange[] ButtonRanges { get; set; }
+
+		public ButtonTextRenderItem(string text, CharacterRange[] buttonRanges)
+		{
+			Text = text;
+			ButtonRanges = buttonRanges;
+		}
+
+		public override void Render(Graphics graphics, Rectangle renderArea, Point mousePointer)
+		{
+			StringFormat stringFormat1 = new StringFormat();
+			stringFormat1.SetMeasurableCharacterRanges(ButtonRanges);
+
+			UpdateRegions = graphics.MeasureCharacterRanges(Text, Font, renderArea, stringFormat1)
+				.Select(x => Rectangle.Round(x.GetBounds(graphics))).ToArray();
+
+			foreach (var region in UpdateRegions)
+			{
+				Brush brush = region.Contains(mousePointer)
+					? SelectedBackingHighlightBrush
+					: BackingHighlightBrush;
+
+				graphics.FillRectangle(brush, region);
+			}
+
+			graphics.DrawString(Text, Font, TextBrush, renderArea);
+		}
+	}
+}

+ 60 - 0
NTERA/Console/RenderItem/ImageRenderItem.cs

@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+
+namespace NTERA.Console
+{
+	public class ImageRenderItem : BaseRenderItem
+	{
+		public Bitmap Image { get; set; }
+
+		public ImageRenderItem(Bitmap bitmap)
+		{
+			Image = bitmap;
+		}
+
+		public ImageRenderItem(Bitmap original, Rectangle cropRectangle)
+		{
+			Image = new Bitmap(original.Width, cropRectangle.Height, PixelFormat.Format32bppArgb);
+
+			using (Graphics g = Graphics.FromImage(Image))
+			{
+				g.DrawImage(original, new Rectangle(0, 0, original.Width, cropRectangle.Height), cropRectangle, GraphicsUnit.Pixel);
+			}
+		}
+
+		public ImageRenderItem(string imagePath)
+		{
+			Image = new Bitmap(imagePath);
+		}
+
+		public override void Render(Graphics graphics, Rectangle renderArea, Point mousePointer)
+		{
+			graphics.DrawImage(Image, new Rectangle(0, renderArea.Y, Image.Width, renderArea.Height));
+		}
+
+		public static List<ImageRenderItem> CreateFromLargeBitmap(Bitmap original, int lineHeight)
+		{
+			List<ImageRenderItem> items = new List<ImageRenderItem>();
+
+			int total = (int)Math.Ceiling(original.Height / (float)lineHeight);
+
+			Rectangle destRect = new Rectangle(0, 0, original.Width, lineHeight);
+
+			for (int i = 0; i < total; i++)
+			{
+				//Bitmap temp = new Bitmap(original.Width, lineHeight, PixelFormat.Format32bppArgb);
+
+				//using (Graphics g = Graphics.FromImage(temp))
+				//{
+				//	g.DrawImage(original, destRect, new Rectangle(0, i * lineHeight, original.Width, lineHeight), GraphicsUnit.Pixel);
+				//}
+
+				items.Add(new ImageRenderItem(original, destRect));
+			}
+
+			return items;
+		}
+	}
+}

+ 37 - 0
NTERA/Console/RenderItem/TextRenderItem.cs

@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+
+namespace NTERA.Console
+{
+	public class TextRenderItem : BaseRenderItem
+	{
+		public Font Font { get; set; } = new Font("MS UI Gothic", 12);
+
+		public SolidBrush TextBrush = new SolidBrush(Color.White);
+
+		public string Text { get; set; }
+
+		public TextRenderItem(string text)
+		{
+			Text = text;
+		}
+
+		public override void Render(Graphics graphics, Rectangle renderArea, Point mousePointer)
+		{
+			graphics.DrawString(Text, Font, TextBrush, renderArea);
+		}
+
+		public static List<TextRenderItem> CreateFromLinedText(string text)
+		{
+			List<TextRenderItem> items = new List<TextRenderItem>();
+
+			foreach (string line in text.Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
+			{
+				items.Add(new TextRenderItem(line));
+			}
+
+			return items;
+		}
+	}
+}

+ 615 - 0
NTERA/Game/Config/Config.cs

@@ -0,0 +1,615 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Text;
+using System.Windows.Forms;
+using MinorShift._Library;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera
+{
+
+	internal static class Config
+	{
+
+		#region config
+
+		public static Encoding Encode = Encoding.GetEncoding("SHIFT-JIS");
+		public static Encoding SaveEncode = Encoding.GetEncoding("SHIFT-JIS");
+		private static Dictionary<ConfigCode, string> _nameDic;
+		public static string GetConfigName(ConfigCode code)
+		{
+			return _nameDic[code];
+		}
+
+		public static void SetConfig(ConfigData instance)
+		{
+			_nameDic = instance.GetConfigNameDic();
+			IgnoreCase = instance.GetConfigValue<bool>(ConfigCode.IgnoreCase);
+			CompatiFunctionNoignoreCase = instance.GetConfigValue<bool>(ConfigCode.CompatiFunctionNoignoreCase);
+			ICFunction = IgnoreCase && !CompatiFunctionNoignoreCase;
+			ICVariable = IgnoreCase;
+			if (IgnoreCase)
+			{
+				if (CompatiFunctionNoignoreCase)
+					SCFunction = StringComparison.Ordinal;
+				else
+					SCFunction = StringComparison.OrdinalIgnoreCase;
+				SCVariable = StringComparison.OrdinalIgnoreCase;
+			}
+			else
+			{
+				SCFunction = StringComparison.Ordinal;
+				SCVariable = StringComparison.Ordinal;
+			}
+			UseRenameFile = instance.GetConfigValue<bool>(ConfigCode.UseRenameFile);
+			UseReplaceFile = instance.GetConfigValue<bool>(ConfigCode.UseReplaceFile);
+			UseMouse = instance.GetConfigValue<bool>(ConfigCode.UseMouse);
+			UseMenu = instance.GetConfigValue<bool>(ConfigCode.UseMenu);
+			UseDebugCommand = instance.GetConfigValue<bool>(ConfigCode.UseDebugCommand);
+			AllowMultipleInstances = instance.GetConfigValue<bool>(ConfigCode.AllowMultipleInstances);
+			AutoSave = instance.GetConfigValue<bool>(ConfigCode.AutoSave);
+			UseKeyMacro = instance.GetConfigValue<bool>(ConfigCode.UseKeyMacro);
+			SizableWindow = instance.GetConfigValue<bool>(ConfigCode.SizableWindow);
+			//UseImageBuffer = instance.GetConfigValue<bool>(ConfigCode.UseImageBuffer);
+			TextDrawingMode = instance.GetConfigValue<TextDrawingMode>(ConfigCode.TextDrawingMode);
+			WindowX = instance.GetConfigValue<int>(ConfigCode.WindowX);
+			WindowY = instance.GetConfigValue<int>(ConfigCode.WindowY);
+			WindowPosX = instance.GetConfigValue<int>(ConfigCode.WindowPosX);
+			WindowPosY = instance.GetConfigValue<int>(ConfigCode.WindowPosY);
+			SetWindowPos = instance.GetConfigValue<bool>(ConfigCode.SetWindowPos);
+			MaxLog = instance.GetConfigValue<int>(ConfigCode.MaxLog);
+			PrintCPerLine = instance.GetConfigValue<int>(ConfigCode.PrintCPerLine);
+			PrintCLength = instance.GetConfigValue<int>(ConfigCode.PrintCLength);
+			ForeColor = instance.GetConfigValue<Color>(ConfigCode.ForeColor);
+			BackColor = instance.GetConfigValue<Color>(ConfigCode.BackColor);
+			FocusColor = instance.GetConfigValue<Color>(ConfigCode.FocusColor);
+			LogColor = instance.GetConfigValue<Color>(ConfigCode.LogColor);
+			FontSize = instance.GetConfigValue<int>(ConfigCode.FontSize);
+			FontName = instance.GetConfigValue<string>(ConfigCode.FontName);
+			LineHeight = instance.GetConfigValue<int>(ConfigCode.LineHeight);
+			FPS = instance.GetConfigValue<int>(ConfigCode.FPS);
+			//SkipFrame = instance.GetConfigValue<int>(ConfigCode.SkipFrame);
+			ScrollHeight = instance.GetConfigValue<int>(ConfigCode.ScrollHeight);
+			InfiniteLoopAlertTime = instance.GetConfigValue<int>(ConfigCode.InfiniteLoopAlertTime);
+			SaveDataNos = instance.GetConfigValue<int>(ConfigCode.SaveDataNos);
+			WarnBackCompatibility = instance.GetConfigValue<bool>(ConfigCode.WarnBackCompatibility);
+			WindowMaximixed = instance.GetConfigValue<bool>(ConfigCode.WindowMaximixed);
+			WarnNormalFunctionOverloading = instance.GetConfigValue<bool>(ConfigCode.WarnNormalFunctionOverloading);
+			SearchSubdirectory = instance.GetConfigValue<bool>(ConfigCode.SearchSubdirectory);
+			SortWithFilename = instance.GetConfigValue<bool>(ConfigCode.SortWithFilename);
+
+			AllowFunctionOverloading = instance.GetConfigValue<bool>(ConfigCode.AllowFunctionOverloading);
+			if (!AllowFunctionOverloading)
+				WarnFunctionOverloading = true;
+			else
+				WarnFunctionOverloading = instance.GetConfigValue<bool>(ConfigCode.WarnFunctionOverloading);
+
+			DisplayWarningLevel = instance.GetConfigValue<int>(ConfigCode.DisplayWarningLevel);
+			DisplayReport = instance.GetConfigValue<bool>(ConfigCode.DisplayReport);
+			ReduceArgumentOnLoad = instance.GetConfigValue<ReduceArgumentOnLoadFlag>(ConfigCode.ReduceArgumentOnLoad);
+			IgnoreUncalledFunction = instance.GetConfigValue<bool>(ConfigCode.IgnoreUncalledFunction);
+			FunctionNotFoundWarning = instance.GetConfigValue<DisplayWarningFlag>(ConfigCode.FunctionNotFoundWarning);
+			FunctionNotCalledWarning = instance.GetConfigValue<DisplayWarningFlag>(ConfigCode.FunctionNotCalledWarning);
+
+
+			ChangeMasterNameIfDebug = instance.GetConfigValue<bool>(ConfigCode.ChangeMasterNameIfDebug);
+			LastKey = instance.GetConfigValue<long>(ConfigCode.LastKey);
+			ButtonWrap = instance.GetConfigValue<bool>(ConfigCode.ButtonWrap);
+
+			TextEditor = instance.GetConfigValue<string>(ConfigCode.TextEditor);
+            EditorType = instance.GetConfigValue<TextEditorType>(ConfigCode.EditorType);
+			EditorArg = instance.GetConfigValue<string>(ConfigCode.EditorArgument);
+
+			CompatiErrorLine = instance.GetConfigValue<bool>(ConfigCode.CompatiErrorLine);
+			CompatiCALLNAME = instance.GetConfigValue<bool>(ConfigCode.CompatiCALLNAME);
+			UseSaveFolder = instance.GetConfigValue<bool>(ConfigCode.UseSaveFolder);
+			CompatiRAND = instance.GetConfigValue<bool>(ConfigCode.CompatiRAND);
+			//CompatiDRAWLINE = instance.GetConfigValue<bool>(ConfigCode.CompatiDRAWLINE);
+			CompatiLinefeedAs1739 = instance.GetConfigValue<bool>(ConfigCode.CompatiLinefeedAs1739);
+			SystemAllowFullSpace = instance.GetConfigValue<bool>(ConfigCode.SystemAllowFullSpace);
+			SystemSaveInUTF8 = instance.GetConfigValue<bool>(ConfigCode.SystemSaveInUTF8);
+			if (SystemSaveInUTF8)
+				SaveEncode = Encoding.GetEncoding("UTF-8");
+			SystemSaveInBinary = instance.GetConfigValue<bool>(ConfigCode.SystemSaveInBinary);
+			SystemIgnoreTripleSymbol = instance.GetConfigValue<bool>(ConfigCode.SystemIgnoreTripleSymbol);
+			
+			CompatiFuncArgAutoConvert = instance.GetConfigValue<bool>(ConfigCode.CompatiFuncArgAutoConvert);
+			CompatiFuncArgOptional = instance.GetConfigValue<bool>(ConfigCode.CompatiFuncArgOptional);
+			CompatiCallEvent = instance.GetConfigValue<bool>(ConfigCode.CompatiCallEvent);
+			CompatiSPChara = instance.GetConfigValue<bool>(ConfigCode.CompatiSPChara);
+
+            AllowLongInputByMouse = instance.GetConfigValue<bool>(ConfigCode.AllowLongInputByMouse);
+
+            TimesNotRigorousCalculation = instance.GetConfigValue<bool>(ConfigCode.TimesNotRigorousCalculation);
+            //一文字変数の禁止オプションを考えた名残
+		    //ForbidOneCodeVariable = instance.GetConfigValue<bool>(ConfigCode.ForbidOneCodeVariable);
+		    SystemNoTarget = instance.GetConfigValue<bool>(ConfigCode.SystemNoTarget);
+
+            CBUseClipboard = instance.GetConfigValue<bool>(ConfigCode.CBUseClipboard);
+            CBIgnoreTags = instance.GetConfigValue<bool>(ConfigCode.CBIgnoreTags);
+            CBReplaceTags = instance.GetConfigValue<string>(ConfigCode.CBReplaceTags);
+            CBNewLinesOnly = instance.GetConfigValue<bool>(ConfigCode.CBNewLinesOnly);
+            CBClearBuffer = instance.GetConfigValue<bool>(ConfigCode.CBClearBuffer);
+            CBTriggerLeftClick = instance.GetConfigValue<bool>(ConfigCode.CBTriggerLeftClick);
+            CBTriggerMiddleClick = instance.GetConfigValue<bool>(ConfigCode.CBTriggerMiddleClick);
+            CBTriggerDoubleLeftClick = instance.GetConfigValue<bool>(ConfigCode.CBTriggerDoubleLeftClick);
+            CBTriggerAnyKeyWait = instance.GetConfigValue<bool>(ConfigCode.CBTriggerAnyKeyWait);
+            CBTriggerInputWait = instance.GetConfigValue<bool>(ConfigCode.CBTriggerInputWait);
+            CBMaxCB = instance.GetConfigValue<int>(ConfigCode.CBMaxCB);
+            CBBufferSize = instance.GetConfigValue<int>(ConfigCode.CBBufferSize);
+            CBScrollCount = instance.GetConfigValue<int>(ConfigCode.CBScrollCount);
+            CBMinTimer = instance.GetConfigValue<int>(ConfigCode.CBMinTimer);
+
+            UseLanguage lang = instance.GetConfigValue<UseLanguage>(ConfigCode.useLanguage);
+            switch (lang)
+            {
+                case UseLanguage.JAPANESE:
+                    Language = 0x0411; LangManager.setEncode(932); break;
+                case UseLanguage.KOREAN:
+                    Language = 0x0412; LangManager.setEncode(949);  break;
+                case UseLanguage.CHINESE_HANS:
+                    Language = 0x0804; LangManager.setEncode(936); break;
+                case UseLanguage.CHINESE_HANT:
+                    Language = 0x0404; LangManager.setEncode(950); break;
+            }
+
+			if (FontSize < 8)
+			{
+				MessageBox.Show("フォントサイズが小さすぎます(8が下限)", "設定のエラー");
+				FontSize = 8;
+			}
+			if (LineHeight < FontSize)
+			{
+				MessageBox.Show("行の高さがフォントサイズより小さいため、フォントサイズと同じ高さと解釈されます", "設定のエラー");
+				LineHeight = FontSize;
+			}
+			if (SaveDataNos < 20)
+			{
+				MessageBox.Show("表示するセーブデータ数が少なすぎます(20が下限)", "設定のエラー");
+				SaveDataNos = 20;
+			}
+			if (SaveDataNos > 80)
+			{
+				MessageBox.Show("表示するセーブデータ数が多すぎます(80が上限)", "設定のエラー");
+				SaveDataNos = 80;
+			}
+			if (MaxLog < 500)
+			{
+				MessageBox.Show("ログ表示行数が少なすぎます(500が下限)", "設定のエラー");
+				MaxLog = 500;
+			}
+
+			DrawingParam_ShapePositionShift = 0;
+			if (TextDrawingMode != TextDrawingMode.WINAPI)
+				DrawingParam_ShapePositionShift = Math.Max(2, FontSize / 6);
+			DrawableWidth = WindowX - DrawingParam_ShapePositionShift;
+
+			if (UseSaveFolder)
+				SavDir = Program.ExeDir + "sav\\";
+			else
+				SavDir = Program.ExeDir;
+			if (UseSaveFolder && !Directory.Exists(SavDir))
+				CreateSaveDirAndMoveFiles();
+		}
+
+
+	    private static readonly Dictionary<string, Dictionary<FontStyle, Font>> FontDic = new Dictionary<string, Dictionary<FontStyle, Font>>();
+		public static Font Font => GetFont(null, FontStyle.Regular);
+
+	    public static Font GetFont(string theFontname, FontStyle style)
+		{
+			string fn = theFontname;
+			if (string.IsNullOrEmpty(theFontname))
+				fn = FontName;
+			if (!FontDic.ContainsKey(fn))
+				FontDic.Add(fn, new Dictionary<FontStyle, Font>());
+			var fontStyleDic = FontDic[fn];
+		    if (fontStyleDic.ContainsKey(style)) return fontStyleDic[style];
+
+		    var fontsize = FontSize;
+		    Font styledFont = null;
+		    try
+		    {
+		        styledFont = new Font(fn, fontsize, style, GraphicsUnit.Pixel);
+		    }
+		    catch
+		    {
+		        return null;
+		    }
+		    fontStyleDic.Add(style, styledFont);
+		    return fontStyleDic[style];
+		}
+
+		public static void ClearFont()
+		{
+			foreach (var fontStyleDicPair in FontDic)
+			{
+				foreach (var pair in fontStyleDicPair.Value)
+				{
+					pair.Value.Dispose();
+				}
+				fontStyleDicPair.Value.Clear();
+			}
+			FontDic.Clear();
+		}
+
+		/// <summary>
+		/// ディレクトリ作成失敗のExceptionは呼び出し元で処理すること
+		/// </summary>
+		public static void CreateSavDir()
+		{
+			if (UseSaveFolder && !Directory.Exists(SavDir))
+			{
+				Directory.CreateDirectory(SavDir);
+			}
+		}
+
+		private static void CreateSaveDirAndMoveFiles()
+		{
+			try
+			{
+				Directory.CreateDirectory(SavDir);
+			}
+			catch
+			{
+				MessageBox.Show("savフォルダの作成に失敗しました", "フォルダ作成失敗");
+				return;
+			}
+			bool existGlobal = File.Exists(Program.ExeDir + "global.sav");
+			string[] savFiles = Directory.GetFiles(Program.ExeDir, "save*.sav", SearchOption.TopDirectoryOnly);
+			if (!existGlobal && savFiles.Length == 0)
+				return;
+			DialogResult result = MessageBox.Show("savフォルダを作成しました\n現在のデータをsavフォルダ内に移動しますか?", "データ移動", MessageBoxButtons.YesNo);
+			if (result != DialogResult.Yes)
+				return;
+			//ダイアログが開いている間にフォルダを消してしまうような邪悪なユーザーがいるかもしれない
+			if (!Directory.Exists(SavDir))
+			{
+				MessageBox.Show("savフォルダの作成が見当たりません", "フォルダ作成失敗");
+				return;
+			}
+			//ダイアログが開いている間にファイルを変更するような邪悪なユーザーがいるかもしれない
+			try
+			{
+				if (File.Exists(Program.ExeDir + "global.sav"))
+					File.Move(Program.ExeDir + "global.sav", SavDir + "global.sav");
+				savFiles = Directory.GetFiles(Program.ExeDir, "save*.sav", SearchOption.TopDirectoryOnly);
+				foreach (string oldpath in savFiles)
+					File.Move(oldpath, SavDir + Path.GetFileName(oldpath));
+			}
+			catch
+			{
+				MessageBox.Show("savファイルの移動に失敗しました", "移動失敗");
+			}
+		}
+		//先にSetConfigを呼ぶこと
+		//戻り値はセーブが必要かどうか
+		public static bool CheckUpdate()
+		{
+			if (ReduceArgumentOnLoad != ReduceArgumentOnLoadFlag.ONCE)
+			{
+			    switch (ReduceArgumentOnLoad)
+			    {
+			        case ReduceArgumentOnLoadFlag.YES:
+			            NeedReduceArgumentOnLoad = true;
+			            break;
+			        case ReduceArgumentOnLoadFlag.NO:
+			            NeedReduceArgumentOnLoad = false;
+			            break;
+			        case ReduceArgumentOnLoadFlag.ONCE:
+			            return false;
+			        default:
+			            throw new ArgumentOutOfRangeException();
+			    }
+			    return false;
+			}
+
+		    var key = GetUpdateKey();
+			var updated = LastKey != key;
+			LastKey = key;
+			return updated;
+		}
+
+		private static long GetUpdateKey()
+		{
+			var option = SearchOption.TopDirectoryOnly;
+			if (SearchSubdirectory)
+				option = SearchOption.AllDirectories;
+			string[] erbFiles = Directory.GetFiles(Program.ErbDir, "*.ERB", option);
+			string[] csvFiles = Directory.GetFiles(Program.CsvDir, "*.CSV", option);
+			var writetimes = new long[erbFiles.Length + csvFiles.Length];
+			for (int i = 0; i < erbFiles.Length; i++)
+				if (Path.GetExtension(erbFiles[i]).Equals(".ERB", StringComparison.OrdinalIgnoreCase))
+					writetimes[i] = File.GetLastWriteTime(erbFiles[i]).ToBinary();
+			for (int i = 0; i < csvFiles.Length; i++)
+				if (Path.GetExtension(csvFiles[i]).Equals(".CSV", StringComparison.OrdinalIgnoreCase))
+					writetimes[i + erbFiles.Length] = File.GetLastWriteTime(csvFiles[i]).ToBinary();
+			long key = 0;
+			for (int i = 0; i < writetimes.Length; i++)
+			{
+				unchecked
+				{
+					key ^= writetimes[i] * 1103515245 + 12345;
+				}
+			}
+			return key;
+		}
+
+
+		public static List<KeyValuePair<string, string>> GetFiles(string rootdir, string pattern)
+		{
+			return getFiles(rootdir, rootdir, pattern, !SearchSubdirectory, SortWithFilename);
+		}
+
+		private sealed class StrIgnoreCaseComparer : IComparer<string>
+		{
+			public int Compare(string x, string y)
+			{
+				return string.Compare(x, y, StringComparison.OrdinalIgnoreCase);
+			}
+		}
+
+	    private static readonly StrIgnoreCaseComparer IgnoreCaseComparer = new StrIgnoreCaseComparer();
+
+		//KeyValuePair<相対パス, 完全パス>のリストを返す。
+		private static List<KeyValuePair<string, string>> getFiles(string dir, string rootdir, string pattern, bool toponly, bool sort)
+		{
+			const StringComparison strComp = StringComparison.OrdinalIgnoreCase;
+			List<KeyValuePair<string, string>> retList = new List<KeyValuePair<string, string>>();
+			if (!toponly)
+			{//サブフォルダ内の検索
+				string[] dirList = Directory.GetDirectories(dir, "*", SearchOption.TopDirectoryOnly);
+				if (dirList.Length > 0)
+				{
+					if (sort)
+						Array.Sort(dirList, IgnoreCaseComparer);
+					for (int i = 0; i < dirList.Length; i++)
+						retList.AddRange(getFiles(dirList[i], rootdir, pattern, toponly, sort));
+				}
+			}
+		    string RelativePath;//相対ディレクトリ名
+			if (string.Equals(dir, rootdir, strComp))//現在のパスが検索ルートパスに等しい
+				RelativePath = "";
+			else
+			{
+				if (!dir.StartsWith(rootdir, strComp))
+					RelativePath = dir;
+				else
+					RelativePath = dir.Substring(rootdir.Length);//前方が検索ルートパスと一致するならその部分を切り取る
+				if (!RelativePath.EndsWith("\\") && !RelativePath.EndsWith("/"))
+					RelativePath += "\\";//末尾が\又は/で終わるように。後でFile名を直接加算できるようにしておく
+			}
+			//filepathsは完全パスである
+			string[] filepaths = Directory.GetFiles(dir, pattern, SearchOption.TopDirectoryOnly);
+			if (sort)
+            {
+                Array.Sort(filepaths, IgnoreCaseComparer);
+            }
+            for (int i = 0; i < filepaths.Length; i++)
+            {
+                if (Path.GetExtension(filepaths[i]).Length <= 4)//".erb"や".csv"であること。放置すると".erb*"等を拾う。
+                {
+                    retList.Add(new KeyValuePair<string, string>(RelativePath + Path.GetFileName(filepaths[i]), filepaths[i]));
+                }
+            }
+
+            return retList;
+		}
+		
+
+		/// <summary>
+		/// IgnoreCaseはprivateに。代わりにICFunctionかICVariableを使う。
+		/// </summary>
+		private static bool IgnoreCase { get; set; }
+		private static bool CompatiFunctionNoignoreCase { get; set; }
+		
+
+		/// <summary>
+		/// 関数名・属性名的な名前のIgnoreCaseフラグ
+		/// 関数・属性・BEGINのキーワード 
+		/// どうせeramaker用の互換処理なのでEmuera専用構文については適当に。
+		/// </summary>
+		public static bool ICFunction { get; private set; }
+		
+		/// <summary>
+		/// 変数名、命令名的な名前のIgnoreCaseフラグ 
+		/// 変数・命令・$ラベル名、GOTOの引数 
+		/// </summary>
+		public static bool ICVariable { get; private set; }
+
+		/// <summary>
+		/// 関数名・属性名的な名前の比較フラグ
+		/// </summary>
+		public static StringComparison SCFunction { get; private set; }
+		/// <summary>
+		/// 変数名、命令名的な名前の比較フラグ
+		/// </summary>
+		public static StringComparison SCVariable { get; private set; }
+		/// <summary>
+		/// ファイル名的な名前の比較フラグ
+		/// </summary>
+		public const StringComparison SCIgnoreCase = StringComparison.OrdinalIgnoreCase;
+		/// <summary>
+		/// 式中での文字列比較フラグ
+		/// </summary>
+		public const StringComparison SCExpression = StringComparison.Ordinal;
+
+		/// <summary>
+		/// GDI+利用時に発生する文字列と図形・画像間の位置ずれ補正
+		/// </summary>
+		public static int DrawingParam_ShapePositionShift { get; private set; }
+
+
+		public static bool UseRenameFile { get; private set; }
+		public static bool UseReplaceFile { get; private set; }
+		public static bool UseMouse { get; private set; }
+		public static bool UseMenu { get; private set; }
+		public static bool UseDebugCommand { get; private set; }
+		public static bool AllowMultipleInstances { get; private set; }
+		public static bool AutoSave { get; private set; }
+		public static bool UseKeyMacro { get; private set; }
+		public static bool SizableWindow { get; private set; }
+		//public static bool UseImageBuffer { get; private set; }
+		public static TextDrawingMode TextDrawingMode { get; private set; }
+		public static int WindowX { get; private set; }
+		/// <summary>
+		/// 実際に描画可能な横幅
+		/// </summary>
+		public static int DrawableWidth { get; private set; }
+		public static int WindowY { get; private set; }
+		public static int WindowPosX { get; private set; }
+		public static int WindowPosY { get; private set; }
+		public static bool SetWindowPos { get; private set; }
+		public static int MaxLog { get; private set; }
+		public static int PrintCPerLine { get; private set; }
+		public static int PrintCLength { get; private set; }
+		public static Color ForeColor { get; private set; }
+		public static Color BackColor { get; private set; }
+		public static Color FocusColor { get; private set; }
+		public static Color LogColor { get; private set; }
+		public static int FontSize { get; private set; }
+		public static string FontName { get; private set; }
+		public static int LineHeight { get; private set; }
+		public static int FPS { get; private set; }
+		//public static int SkipFrame { get; private set; }
+		public static int ScrollHeight { get; private set; }
+		public static int InfiniteLoopAlertTime { get; private set; }
+		public static int SaveDataNos { get; private set; }
+		public static bool WarnBackCompatibility { get; private set; }
+		public static bool WindowMaximixed { get; private set; }
+		public static bool WarnNormalFunctionOverloading { get; private set; }
+		public static bool SearchSubdirectory { get; private set; }
+		public static bool SortWithFilename { get; private set; }
+
+		public static bool AllowFunctionOverloading { get; private set; }
+		public static bool WarnFunctionOverloading { get; private set; }
+
+		public static int DisplayWarningLevel { get; private set; }
+		public static bool DisplayReport { get; private set; }
+		public static ReduceArgumentOnLoadFlag ReduceArgumentOnLoad { get; private set; }
+		public static bool IgnoreUncalledFunction { get; private set; }
+		public static DisplayWarningFlag FunctionNotFoundWarning { get; private set; }
+		public static DisplayWarningFlag FunctionNotCalledWarning { get; private set; }
+
+		public static bool ChangeMasterNameIfDebug { get; private set; }
+		public static long LastKey { get; private set; }
+		public static bool ButtonWrap { get; private set; }
+
+		public static string TextEditor { get; private set; }
+        public static TextEditorType EditorType { get; private set; }
+		public static string EditorArg { get; private set; }
+
+		public static bool CompatiErrorLine { get; private set; }
+		public static bool CompatiCALLNAME { get; private set; }
+		public static bool UseSaveFolder { get; private set; }
+		public static bool CompatiRAND { get; private set; }
+		//public static bool CompatiDRAWLINE { get; private set; }
+		public static bool CompatiLinefeedAs1739 { get; private set; }
+		public static bool SystemAllowFullSpace { get; private set; }
+		public static bool SystemSaveInUTF8 { get; private set; }
+		public static bool SystemSaveInBinary { get; private set; }
+		public static bool CompatiFuncArgAutoConvert { get; private set; }
+		public static bool CompatiFuncArgOptional { get; private set; }
+		public static bool CompatiCallEvent { get; private set; }
+		public static bool CompatiSPChara { get; private set; }
+		public static bool SystemIgnoreTripleSymbol { get; private set; }
+		public static bool SystemNoTarget { get; private set; }
+
+        public static bool CBUseClipboard { get; private set; }
+        public static bool CBIgnoreTags { get; private set; }
+        public static string CBReplaceTags { get; private set; }
+        public static bool CBNewLinesOnly { get; private set; }
+        public static bool CBClearBuffer { get; private set; }
+        public static bool CBTriggerLeftClick { get; private set; }
+        public static bool CBTriggerMiddleClick { get; private set; }
+        public static bool CBTriggerDoubleLeftClick { get; private set; }
+        public static bool CBTriggerAnyKeyWait { get; private set; }
+        public static bool CBTriggerInputWait { get; private set; }
+        public static int  CBMaxCB { get; private set; }
+        public static int  CBBufferSize { get; private set; }
+        public static int  CBScrollCount { get; private set; }
+        public static int  CBMinTimer { get; private set; }
+
+
+        public static int Language { get; private set; }
+		
+		public static string SavDir { get; private set; }
+
+		public static bool NeedReduceArgumentOnLoad { get; private set; }
+
+        public static bool AllowLongInputByMouse { get; private set; }
+
+        public static bool TimesNotRigorousCalculation { get; private set; }
+        //一文字変数の禁止オプションを考えた名残
+        //public static bool ForbidOneCodeVariable { get; private set; }
+		#endregion
+
+		#region debug
+		public static void SetDebugConfig(ConfigData instance)
+		{
+			DebugShowWindow = instance.GetConfigValue<bool>(ConfigCode.DebugShowWindow);
+			DebugWindowTopMost = instance.GetConfigValue<bool>(ConfigCode.DebugWindowTopMost);
+			DebugWindowWidth = instance.GetConfigValue<int>(ConfigCode.DebugWindowWidth);
+			DebugWindowHeight = instance.GetConfigValue<int>(ConfigCode.DebugWindowHeight);
+			DebugSetWindowPos = instance.GetConfigValue<bool>(ConfigCode.DebugSetWindowPos);
+			DebugWindowPosX = instance.GetConfigValue<int>(ConfigCode.DebugWindowPosX);
+			DebugWindowPosY = instance.GetConfigValue<int>(ConfigCode.DebugWindowPosY);
+		}
+		public static bool DebugShowWindow { get; private set; }
+		public static bool DebugWindowTopMost { get; private set; }
+		public static int DebugWindowWidth { get; private set; }
+		public static int DebugWindowHeight { get; private set; }
+		public static bool DebugSetWindowPos { get; private set; }
+		public static int DebugWindowPosX { get; private set; }
+		public static int DebugWindowPosY { get; private set; }
+
+
+		#endregion
+
+		#region replace
+		public static void SetReplace(ConfigData instance)
+		{
+			MoneyLabel = instance.GetConfigValue<string>(ConfigCode.MoneyLabel);
+			MoneyFirst = instance.GetConfigValue<bool>(ConfigCode.MoneyFirst);
+			LoadLabel = instance.GetConfigValue<string>(ConfigCode.LoadLabel);
+			MaxShopItem = instance.GetConfigValue<int>(ConfigCode.MaxShopItem);
+			DrawLineString = instance.GetConfigValue<string>(ConfigCode.DrawLineString);
+			if (string.IsNullOrEmpty(DrawLineString))
+				DrawLineString = "-";
+			BarChar1 = instance.GetConfigValue<char>(ConfigCode.BarChar1);
+			BarChar2 = instance.GetConfigValue<char>(ConfigCode.BarChar2);
+			TitleMenuString0 = instance.GetConfigValue<string>(ConfigCode.TitleMenuString0);
+			TitleMenuString1 = instance.GetConfigValue<string>(ConfigCode.TitleMenuString1);
+			ComAbleDefault = instance.GetConfigValue<int>(ConfigCode.ComAbleDefault);
+			StainDefault = instance.GetConfigValue<List<Int64>>(ConfigCode.StainDefault);
+			TimeupLabel = instance.GetConfigValue<string>(ConfigCode.TimeupLabel);
+			ExpLvDef = instance.GetConfigValue<List<Int64>>(ConfigCode.ExpLvDef);
+			PalamLvDef = instance.GetConfigValue<List<Int64>>(ConfigCode.PalamLvDef);
+			PbandDef = instance.GetConfigValue<Int64>(ConfigCode.pbandDef);
+            RelationDef = instance.GetConfigValue<Int64>(ConfigCode.RelationDef);
+		}
+
+		public static string MoneyLabel { get; private set; }
+		public static bool MoneyFirst { get; private set; }
+		public static string LoadLabel { get; private set; }
+		public static int MaxShopItem { get; private set; }
+		public static string DrawLineString { get; private set; }
+		public static char BarChar1 { get; private set; }
+		public static char BarChar2 { get; private set; }
+		public static string TitleMenuString0 { get; private set; }
+		public static string TitleMenuString1 { get; private set; }
+		public static int ComAbleDefault { get; private set; }
+		public static List<Int64> StainDefault { get; private set; }
+		public static string TimeupLabel { get; private set; }
+		public static List<Int64> ExpLvDef { get; private set; }
+		public static List<Int64> PalamLvDef { get; private set; }
+		public static Int64 PbandDef { get; private set; }
+        public static Int64 RelationDef { get; private set; }
+		#endregion
+		
+		
+		
+	}
+}

+ 170 - 0
NTERA/Game/Config/ConfigCode.cs

@@ -0,0 +1,170 @@
+
+using System.Reflection;
+
+namespace MinorShift.Emuera
+{
+	//難読化用属性。enum.ToString()やenum.Parse()を行うなら(Exclude=true)にすること。
+	[Obfuscation(Exclude=true)]
+	internal enum DisplayWarningFlag
+	{
+		IGNORE = 0,
+		LATER = 1,
+		ONCE = 2,
+		DISPLAY = 3
+	}
+
+	[Obfuscation(Exclude=true)]
+	internal enum ReduceArgumentOnLoadFlag
+	{
+		YES = 0,
+		ONCE = 1,
+		NO = 2
+	}
+
+	[Obfuscation(Exclude=true)]
+	public enum TextDrawingMode
+	{
+		GRAPHICS = 0,
+		TEXTRENDERER = 1,
+		WINAPI = 2
+	}
+
+    [Obfuscation(Exclude = true)]
+    internal enum UseLanguage
+    {
+        JAPANESE = 0,
+        KOREAN = 1,
+        CHINESE_HANS = 2,
+        CHINESE_HANT = 3        
+    }
+
+    [Obfuscation(Exclude = true)]
+    internal enum TextEditorType
+    {
+        SAKURA = 0,
+        TERAPAD = 1,
+        EMEDITOR = 2,
+        USER_SETTING = 3
+    }
+
+	//数字に意味は無い。
+	[Obfuscation(Exclude = true)]
+	internal enum ConfigCode
+	{
+		IgnoreCase = 0,
+		UseRenameFile = 1,
+		UseReplaceFile = 2,
+		UseMouse = 3,
+		UseMenu = 4,
+		UseDebugCommand = 5,
+		AllowMultipleInstances = 6,
+		AutoSave = 7,
+		SizableWindow = 8,
+		TextDrawingMode = 9,
+		UseImageBuffer = 10,
+		WindowX = 11,
+		WindowY = 12,
+		MaxLog = 13,
+		PrintCPerLine = 14,
+		PrintCLength = 15,
+		FontName = 16,
+		FontSize = 17,
+		LineHeight = 18,
+		ForeColor = 19,
+		BackColor = 20,
+		FocusColor = 21,
+		LogColor = 22,
+		FPS = 23,
+		SkipFrame = 24,
+		InfiniteLoopAlertTime = 25,
+		DisplayWarningLevel = 26,
+		DisplayReport = 27,
+		ReduceArgumentOnLoad = 28,
+		//ReduceFormattedStringOnLoad = 29,
+		IgnoreUncalledFunction = 30,
+		FunctionNotFoundWarning = 31,
+		FunctionNotCalledWarning = 32,
+		//IgnoreWarningFiles = 33,
+		ChangeMasterNameIfDebug = 34,
+		LastKey = 35,
+		ButtonWrap = 36,
+		SearchSubdirectory = 37,
+		SortWithFilename = 38,
+		SetWindowPos = 39,
+		WindowPosX = 40,
+		WindowPosY = 41,
+		ScrollHeight = 42,
+		SaveDataNos = 43,
+		WarnBackCompatibility = 44,
+		AllowFunctionOverloading = 45,
+		WarnFunctionOverloading = 46,
+		WindowMaximixed = 47,
+		TextEditor = 48,
+        EditorType = 99,
+		EditorArgument = 49,
+		WarnNormalFunctionOverloading = 50,
+		CompatiErrorLine = 51,
+		CompatiCALLNAME = 52,
+		DebugShowWindow = 53,
+		DebugWindowTopMost = 54,
+		DebugWindowWidth = 55,
+		DebugWindowHeight = 56,
+		DebugSetWindowPos = 57,
+		DebugWindowPosX = 58,
+		DebugWindowPosY = 59,
+		UseSaveFolder = 60,
+		CompatiRAND = 61,
+		CompatiDRAWLINE = 62,
+		CompatiFunctionNoignoreCase,
+		SystemAllowFullSpace,
+		SystemSaveInUTF8,
+		CompatiLinefeedAs1739,
+        useLanguage,
+		SystemSaveInBinary,
+		CompatiFuncArgAutoConvert,
+		CompatiFuncArgOptional,
+		AllowLongInputByMouse,
+		CompatiCallEvent,
+		SystemIgnoreTripleSymbol,
+		CompatiSPChara,
+        TimesNotRigorousCalculation,
+        //一文字変数の禁止オプションを考えた名残
+        //ForbidOneCodeVariable,
+		SystemNoTarget,
+
+        CBUseClipboard,
+        CBIgnoreTags,
+        CBReplaceTags,
+        CBNewLinesOnly,
+        CBClearBuffer,
+        CBTriggerLeftClick,
+        CBTriggerMiddleClick,
+        CBTriggerDoubleLeftClick,
+        CBTriggerAnyKeyWait,
+        CBTriggerInputWait,
+        CBMaxCB,
+        CBBufferSize,
+        CBScrollCount,
+        CBMinTimer,
+        AnchorCustomIcon, // Takes a path relative to the exe, or an absolute path.
+
+		MoneyLabel = 100,
+		MoneyFirst = 101,
+		LoadLabel = 102,
+		MaxShopItem = 103,
+		DrawLineString = 104,
+		BarChar1 = 105,
+		BarChar2 = 106,
+		TitleMenuString0 = 107,
+		TitleMenuString1 = 108,
+		ComAbleDefault = 109,
+		StainDefault = 110,
+		TimeupLabel = 111,
+		ExpLvDef = 112,
+		PalamLvDef = 113,
+		pbandDef = 114,
+        RelationDef = 115,
+
+		UseKeyMacro = 162
+	}
+}

+ 660 - 0
NTERA/Game/Config/ConfigData.cs

@@ -0,0 +1,660 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.Sub;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera
+{
+	/// <summary>
+	/// プログラム全体で使用される値でWindow作成前に設定して以後変更されないもの
+	/// (という予定だったが今は違う)
+	/// 1756 Config → ConfigDataへ改名
+	/// </summary>
+	internal sealed class ConfigData
+	{
+		static readonly string configPath = Program.ExeDir + "emuera.config";
+		static readonly string configdebugPath = Program.DebugDir + "debug.config";
+
+		static ConfigData() { }
+		private static ConfigData instance = new ConfigData();
+		public static ConfigData Instance => instance;
+
+		private ConfigData() { setDefault(); }
+
+		//適当に大き目の配列を作っておく。
+		private AConfigItem[] configArray = new AConfigItem[85];
+		private AConfigItem[] replaceArray = new AConfigItem[50];
+		private AConfigItem[] debugArray = new AConfigItem[20];
+
+		private void setDefault()
+		{
+			int i = 0;
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.IgnoreCase, "大文字小文字の違いを無視する", true);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.UseRenameFile, "_Rename.csvを利用する", false);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.UseReplaceFile, "_Replace.csvを利用する", true);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.UseMouse, "マウスを使用する", true);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.UseMenu, "メニューを使用する", true);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.UseDebugCommand, "デバッグコマンドを使用する", false);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.AllowMultipleInstances, "多重起動を許可する", true);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.AutoSave, "オートセーブを行なう", true);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.UseKeyMacro, "キーボードマクロを使用する", true);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.SizableWindow, "ウィンドウの高さを可変にする", true);
+			configArray[i++] = new ConfigItem<TextDrawingMode>(ConfigCode.TextDrawingMode, "描画インターフェース", TextDrawingMode.GRAPHICS);
+			//configArray[i++] = new ConfigItem<bool>(ConfigCode.UseImageBuffer, "イメージバッファを使用する", true);
+			configArray[i++] = new ConfigItem<int>(ConfigCode.WindowX, "ウィンドウ幅", 760);
+			configArray[i++] = new ConfigItem<int>(ConfigCode.WindowY, "ウィンドウ高さ", 480);
+			configArray[i++] = new ConfigItem<int>(ConfigCode.WindowPosX, "ウィンドウ位置X", 0);
+			configArray[i++] = new ConfigItem<int>(ConfigCode.WindowPosY, "ウィンドウ位置Y", 0);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.SetWindowPos, "起動時のウィンドウ位置を指定する", false);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.WindowMaximixed, "起動時にウィンドウを最大化する", false);
+			configArray[i++] = new ConfigItem<int>(ConfigCode.MaxLog, "履歴ログの行数", 5000);
+			configArray[i++] = new ConfigItem<int>(ConfigCode.PrintCPerLine, "PRINTCを並べる数", 3);
+			configArray[i++] = new ConfigItem<int>(ConfigCode.PrintCLength, "PRINTCの文字数", 25);
+			configArray[i++] = new ConfigItem<string>(ConfigCode.FontName, "フォント名", "MS ゴシック");
+			configArray[i++] = new ConfigItem<int>(ConfigCode.FontSize, "フォントサイズ", 18);
+			configArray[i++] = new ConfigItem<int>(ConfigCode.LineHeight, "一行の高さ", 19);
+			configArray[i++] = new ConfigItem<Color>(ConfigCode.ForeColor, "文字色", Color.FromArgb(192, 192, 192));//LIGHTGRAY
+			configArray[i++] = new ConfigItem<Color>(ConfigCode.BackColor, "背景色", Color.FromArgb(0, 0, 0));//BLACK
+			configArray[i++] = new ConfigItem<Color>(ConfigCode.FocusColor, "選択中文字色", Color.FromArgb(255, 255, 0));//YELLOW
+			configArray[i++] = new ConfigItem<Color>(ConfigCode.LogColor, "履歴文字色", Color.FromArgb(192, 192, 192));//LIGHTGRAY//Color.FromArgb(128, 128, 128);//GRAY
+			configArray[i++] = new ConfigItem<int>(ConfigCode.FPS, "フレーム毎秒", 5);
+			configArray[i++] = new ConfigItem<int>(ConfigCode.SkipFrame, "最大スキップフレーム数", 3);
+			configArray[i++] = new ConfigItem<int>(ConfigCode.ScrollHeight, "スクロール行数", 1);
+			configArray[i++] = new ConfigItem<int>(ConfigCode.InfiniteLoopAlertTime, "無限ループ警告までのミリ秒数", 5000);
+			configArray[i++] = new ConfigItem<int>(ConfigCode.DisplayWarningLevel, "表示する最低警告レベル", 1);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.DisplayReport, "ロード時にレポートを表示する", false);
+			configArray[i++] = new ConfigItem<ReduceArgumentOnLoadFlag>(ConfigCode.ReduceArgumentOnLoad, "ロード時に引数を解析する", ReduceArgumentOnLoadFlag.NO);
+			//configArray[i++] = new ConfigItem<bool>(ConfigCode.ReduceFormattedStringOnLoad, "ロード時にFORM文字列を解析する", true);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.IgnoreUncalledFunction, "呼び出されなかった関数を無視する", true);
+			configArray[i++] = new ConfigItem<DisplayWarningFlag>(ConfigCode.FunctionNotFoundWarning, "関数が見つからない警告の扱い", DisplayWarningFlag.IGNORE);
+			configArray[i++] = new ConfigItem<DisplayWarningFlag>(ConfigCode.FunctionNotCalledWarning, "関数が呼び出されなかった警告の扱い", DisplayWarningFlag.IGNORE);
+			//configArray[i++] = new ConfigItem<List<string>>(ConfigCode.IgnoreWarningFiles, "指定したファイル中の警告を無視する", new List<string>());
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.ChangeMasterNameIfDebug, "デバッグコマンドを使用した時にMASTERの名前を変更する", true);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.ButtonWrap, "ボタンの途中で行を折りかえさない", false);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.SearchSubdirectory, "サブディレクトリを検索する", false);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.SortWithFilename, "読み込み順をファイル名順にソートする", false);
+			configArray[i++] = new ConfigItem<long>(ConfigCode.LastKey, "最終更新コード", 0);
+			configArray[i++] = new ConfigItem<int>(ConfigCode.SaveDataNos, "表示するセーブデータ数", 20);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.WarnBackCompatibility, "eramaker互換性に関する警告を表示する", true);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.AllowFunctionOverloading, "システム関数の上書きを許可する", true);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.WarnFunctionOverloading, "システム関数が上書きされたとき警告を表示する", true);
+			configArray[i++] = new ConfigItem<string>(ConfigCode.TextEditor, "関連づけるテキストエディタ", "notepad");
+            configArray[i++] = new ConfigItem<TextEditorType>(ConfigCode.EditorType, "テキストエディタコマンドライン指定", TextEditorType.USER_SETTING);
+			configArray[i++] = new ConfigItem<string>(ConfigCode.EditorArgument, "エディタに渡す行指定引数", "");
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.WarnNormalFunctionOverloading, "同名の非イベント関数が複数定義されたとき警告する", false);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.CompatiErrorLine, "解釈不可能な行があっても実行する", false);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.CompatiCALLNAME, "CALLNAMEが空文字列の時にNAMEを代入する", false);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.UseSaveFolder, "セーブデータをsavフォルダ内に作成する", false);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.CompatiRAND, "擬似変数RANDの仕様をeramakerに合わせる", false);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.CompatiDRAWLINE, "DRAWLINEを常に新しい行で行う", false);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.CompatiFunctionNoignoreCase, "関数・属性については大文字小文字を無視しない", false); ;
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.SystemAllowFullSpace, "全角スペースをホワイトスペースに含める", true);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.SystemSaveInUTF8, "セーブデータをUTF-8で保存する", false);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.CompatiLinefeedAs1739, "ver1739以前の非ボタン折り返しを再現する", false);
+            configArray[i++] = new ConfigItem<UseLanguage>(ConfigCode.useLanguage, "内部で使用する東アジア言語", UseLanguage.JAPANESE);
+            configArray[i++] = new ConfigItem<bool>(ConfigCode.AllowLongInputByMouse, "ONEINPUT系命令でマウスによる2文字以上の入力を許可する", false);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.CompatiCallEvent, "イベント関数のCALLを許可する", false);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.CompatiSPChara, "SPキャラを使用する", false);
+			
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.SystemSaveInBinary, "セーブデータをバイナリ形式で保存する", true);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.CompatiFuncArgOptional, "ユーザー関数の全ての引数の省略を許可する", false);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.CompatiFuncArgAutoConvert, "ユーザー関数の引数に自動的にTOSTRを補完する", false);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.SystemIgnoreTripleSymbol, "FORM中の三連記号を展開しない", false);
+            configArray[i++] = new ConfigItem<bool>(ConfigCode.TimesNotRigorousCalculation, "TIMESの計算をeramakerにあわせる", false);
+            //一文字変数の禁止オプションを考えた名残
+			//configArray[i++] = new ConfigItem<bool>(ConfigCode.ForbidOneCodeVariable, "一文字変数の使用を禁止する", false);
+			configArray[i++] = new ConfigItem<bool>(ConfigCode.SystemNoTarget, "キャラクタ変数の引数を補完しない", false);
+
+            configArray[i++] = new ConfigItem<bool>(ConfigCode.CBUseClipboard, "Clipboard- Copy text to Clipboard during Game", true);
+            configArray[i++] = new ConfigItem<bool>(ConfigCode.CBIgnoreTags, "Clipboard- ignore <> tags in text", false);
+            configArray[i++] = new ConfigItem<string>(ConfigCode.CBReplaceTags, "Clipboard- Replace <> with this", ".");
+            configArray[i++] = new ConfigItem<bool>(ConfigCode.CBNewLinesOnly, "Clipboard- Show new lines only", true);
+            configArray[i++] = new ConfigItem<bool>(ConfigCode.CBClearBuffer, "Clipboard- Clear Buffer when game clears screen", false);
+            configArray[i++] = new ConfigItem<bool>(ConfigCode.CBTriggerLeftClick, "Clipboard- LeftClick Trigger", true);
+            configArray[i++] = new ConfigItem<bool>(ConfigCode.CBTriggerMiddleClick, "Clipboard- MiddleClick Trigger", false);
+            configArray[i++] = new ConfigItem<bool>(ConfigCode.CBTriggerDoubleLeftClick, "Clipboard- Double Left Click Trigger", false);
+            configArray[i++] = new ConfigItem<bool>(ConfigCode.CBTriggerAnyKeyWait, "Clipboard- AnyKey Wait Trigger ", false);
+            configArray[i++] = new ConfigItem<bool>(ConfigCode.CBTriggerInputWait, "Clipboard- Wait for Input Trigger", true);
+            configArray[i++] = new ConfigItem<int>(ConfigCode.CBMaxCB, "Clipboard- Length of Clipboard", 25);
+            configArray[i++] = new ConfigItem<int>(ConfigCode.CBBufferSize, "Clipboard- Buffer Size", 300);
+            configArray[i++] = new ConfigItem<int>(ConfigCode.CBScrollCount, "Clipboard- Scrolled Lines per Key", 5);
+            configArray[i++] = new ConfigItem<int>(ConfigCode.CBMinTimer, "Clipboard- min time between pastes", 800);
+            configArray[i++] = new ConfigItem<string>(ConfigCode.AnchorCustomIcon, "Anchor- Path to a custom window icon (PNG)", "");
+
+
+            i = 0;
+			debugArray[i++] = new ConfigItem<bool>(ConfigCode.DebugShowWindow, "起動時にデバッグウインドウを表示する", true);
+			debugArray[i++] = new ConfigItem<bool>(ConfigCode.DebugWindowTopMost, "デバッグウインドウを最前面に表示する", true);
+			debugArray[i++] = new ConfigItem<int>(ConfigCode.DebugWindowWidth, "デバッグウィンドウ幅", 400);
+			debugArray[i++] = new ConfigItem<int>(ConfigCode.DebugWindowHeight, "デバッグウィンドウ高さ", 300);
+			debugArray[i++] = new ConfigItem<bool>(ConfigCode.DebugSetWindowPos, "デバッグウィンドウ位置を指定する", false);
+			debugArray[i++] = new ConfigItem<int>(ConfigCode.DebugWindowPosX, "デバッグウィンドウ位置X", 0);
+			debugArray[i++] = new ConfigItem<int>(ConfigCode.DebugWindowPosY, "デバッグウィンドウ位置Y", 0);
+
+			i = 0;
+			replaceArray[i++] = new ConfigItem<string>(ConfigCode.MoneyLabel, "お金の単位", "$");
+			replaceArray[i++] = new ConfigItem<bool>(ConfigCode.MoneyFirst, "単位の位置", true);
+			replaceArray[i++] = new ConfigItem<string>(ConfigCode.LoadLabel, "起動時簡略表示", "Now Loading...");
+			replaceArray[i++] = new ConfigItem<int>(ConfigCode.MaxShopItem, "販売アイテム数", 100);
+			replaceArray[i++] = new ConfigItem<string>(ConfigCode.DrawLineString, "DRAWLINE文字", "-");
+			replaceArray[i++] = new ConfigItem<char>(ConfigCode.BarChar1, "BAR文字1", '*');
+			replaceArray[i++] = new ConfigItem<char>(ConfigCode.BarChar2, "BAR文字2", '.');
+			replaceArray[i++] = new ConfigItem<string>(ConfigCode.TitleMenuString0, "システムメニュー0", "Start a game");
+			replaceArray[i++] = new ConfigItem<string>(ConfigCode.TitleMenuString1, "システムメニュー1", "Load a save");
+			replaceArray[i++] = new ConfigItem<int>(ConfigCode.ComAbleDefault, "COM_ABLE初期値", 1);
+			replaceArray[i++] = new ConfigItem<List<Int64>>(ConfigCode.StainDefault, "汚れの初期値", new List<Int64>(new Int64[] { 0, 0, 2, 1, 8 }));
+			replaceArray[i++] = new ConfigItem<string>(ConfigCode.TimeupLabel, "時間切れ表示", "時間切れ");
+			replaceArray[i++] = new ConfigItem<List<Int64>>(ConfigCode.ExpLvDef, "EXPLVの初期値", new List<long>(new Int64[] { 0, 1, 4, 20, 50, 200 }));
+			replaceArray[i++] = new ConfigItem<List<Int64>>(ConfigCode.PalamLvDef, "PALAMLVの初期値", new List<long>(new Int64[] { 0, 100, 500, 3000, 10000, 30000, 60000, 100000, 150000, 250000 }));
+			replaceArray[i++] = new ConfigItem<Int64>(ConfigCode.pbandDef, "PBANDの初期値", 4);
+            replaceArray[i++] = new ConfigItem<Int64>(ConfigCode.RelationDef, "RELATIONの初期値", 0);
+		}
+        
+		public ConfigData Copy()
+		{
+			ConfigData config = new ConfigData();
+			for (int i = 0; i < configArray.Length; i++)
+				if ((configArray[i] != null) && (config.configArray[i] != null))
+					configArray[i].CopyTo(config.configArray[i]);
+			for (int i = 0; i < configArray.Length; i++)
+				if ((configArray[i] != null) && (config.configArray[i] != null))
+					configArray[i].CopyTo(config.configArray[i]);
+			for (int i = 0; i < replaceArray.Length; i++)
+				if ((replaceArray[i] != null) && (config.replaceArray[i] != null))
+					replaceArray[i].CopyTo(config.replaceArray[i]);
+			return config;
+		}
+
+		public Dictionary<ConfigCode,string> GetConfigNameDic()
+		{
+			Dictionary<ConfigCode, string> ret = new Dictionary<ConfigCode, string>();
+			foreach (AConfigItem item in configArray)
+			{
+				if (item != null)
+					ret.Add(item.Code, item.Text);
+			}
+			return ret;
+		}
+
+		public T GetConfigValue<T>(ConfigCode code)
+		{
+			AConfigItem item = GetItem(code);
+            //if ((item != null) && (item is ConfigItem<T>))
+				return ((ConfigItem<T>)item).Value;
+            //throw new ExeEE("GetConfigValueのCodeまたは型が不適切");
+		}
+
+#region getitem
+		public AConfigItem GetItem(ConfigCode code)
+		{
+			AConfigItem item = GetConfigItem(code);
+            if (item == null)
+            {
+                item = GetReplaceItem(code);
+	            if (item == null)
+	            {
+	                item = GetDebugItem(code);
+	            }
+            }
+			return item;
+		}
+		public AConfigItem GetItem(string key)
+		{
+			AConfigItem item = GetConfigItem(key);
+			if (item == null)
+			{
+				item = GetReplaceItem(key);
+	            if (item == null)
+	            {
+					item = GetDebugItem(key);
+	            }
+	        }
+			return item;
+		}
+
+		public AConfigItem GetConfigItem(ConfigCode code)
+		{
+			foreach (AConfigItem item in configArray)
+			{
+				if (item == null)
+					continue;
+				if (item.Code == code)
+					return item;
+			}
+			return null;
+		}
+		public AConfigItem GetConfigItem(string key)
+		{
+			foreach (AConfigItem item in configArray)
+			{
+				if (item == null)
+					continue;
+				if (item.Name == key)
+					return item;
+				if (item.Text == key)
+					return item;
+			}
+			return null;
+		}
+
+		public AConfigItem GetReplaceItem(ConfigCode code)
+		{
+			foreach (AConfigItem item in replaceArray)
+			{
+				if (item == null)
+					continue;
+				if (item.Code == code)
+					return item;
+			}
+			return null;
+		}
+		public AConfigItem GetReplaceItem(string key)
+		{
+			foreach (AConfigItem item in replaceArray)
+			{
+				if (item == null)
+					continue;
+				if (item.Name == key)
+					return item;
+				if (item.Text == key)
+					return item;
+			}
+			return null;
+		}
+		
+		public AConfigItem GetDebugItem(ConfigCode code)
+		{
+			foreach (AConfigItem item in debugArray)
+			{
+				if (item == null)
+					continue;
+				if (item.Code == code)
+					return item;
+			}
+			return null;
+		}
+		public AConfigItem GetDebugItem(string key)
+		{
+			foreach (AConfigItem item in debugArray)
+			{
+				if (item == null)
+					continue;
+				if (item.Name == key)
+					return item;
+				if (item.Text == key)
+					return item;
+			}
+			return null;
+		}
+		
+		public SingleTerm GetConfigValueInERB(string text, ref string errMes)
+		{
+			AConfigItem item = Instance.GetItem(text);
+			if(item == null)
+			{
+				errMes = "文字列\"" + text + "\"は適切なコンフィグ名ではありません";
+				return null;
+			}
+			SingleTerm term;
+			switch(item.Code)
+			{
+				//<bool>
+				case ConfigCode.AutoSave://"オートセーブを行なう"
+				case ConfigCode.MoneyFirst://"単位の位置"
+					if(item.GetValue<bool>())
+						term = new SingleTerm(1);
+					else
+						term = new SingleTerm(0);
+					break;
+				//<int>
+				case ConfigCode.WindowX:// "ウィンドウ幅"
+				case ConfigCode.PrintCPerLine:// "PRINTCを並べる数"
+				case ConfigCode.PrintCLength:// "PRINTCの文字数"
+				case ConfigCode.FontSize:// "フォントサイズ"
+				case ConfigCode.LineHeight:// "一行の高さ"
+				case ConfigCode.SaveDataNos:// "表示するセーブデータ数"
+				case ConfigCode.MaxShopItem:// "販売アイテム数"
+				case ConfigCode.ComAbleDefault:// "COM_ABLE初期値"
+					term = new SingleTerm(item.GetValue<int>());
+					break;
+				//<Color>
+				case ConfigCode.ForeColor://"文字色"
+				case ConfigCode.BackColor://"背景色"
+				case ConfigCode.FocusColor://"選択中文字色"
+				case ConfigCode.LogColor://"履歴文字色"
+					{
+						Color color = item.GetValue<Color>();
+						term = new SingleTerm( ((color.R * 256) + color.G) * 256 + color.B);
+					}
+					break;
+
+				//<Int64>
+				case ConfigCode.pbandDef:// "PBANDの初期値"
+				case ConfigCode.RelationDef:// "RELATIONの初期値"
+					term = new SingleTerm(item.GetValue<Int64>());
+					break;
+
+				//<string>
+				case ConfigCode.FontName:// "フォント名"
+				case ConfigCode.MoneyLabel:// "お金の単位"
+				case ConfigCode.LoadLabel:// "起動時簡略表示"
+				case ConfigCode.DrawLineString:// "DRAWLINE文字"
+				case ConfigCode.TitleMenuString0:// "システムメニュー0"
+				case ConfigCode.TitleMenuString1:// "システムメニュー1"
+				case ConfigCode.TimeupLabel:// "時間切れ表示"
+					term = new SingleTerm(item.GetValue<string>());
+					break;
+				
+				//<char>
+				case ConfigCode.BarChar1:// "BAR文字1"
+				case ConfigCode.BarChar2:// "BAR文字2"
+					term = new SingleTerm(item.GetValue<char>().ToString());
+					break;
+				//<TextDrawingMode>
+				case ConfigCode.TextDrawingMode:// "描画インターフェース"
+					term = new SingleTerm(item.GetValue<TextDrawingMode>().ToString());
+					break;
+				default:
+				{
+					errMes = "コンフィグ文字列\"" + text + "\"の値の取得は許可されていません";
+					return null;
+				}
+			}
+			return term;
+		}
+#endregion
+
+
+		public bool SaveConfig()
+		{
+			StreamWriter writer = null;
+
+			try
+			{
+				writer = new StreamWriter(configPath, false, Config.Encode);
+				for (int i = 0; i < configArray.Length; i++)
+				{
+					AConfigItem item = configArray[i];
+					if (item == null)
+						continue;
+					
+					//1806beta001 CompatiDRAWLINEの廃止、CompatiLinefeedAs1739へ移行
+					if (item.Code == ConfigCode.CompatiDRAWLINE)
+						continue;
+					if ((item.Code == ConfigCode.ChangeMasterNameIfDebug) && (item.GetValue<bool>()))
+						continue;
+					if ((item.Code == ConfigCode.LastKey) && (item.GetValue<long>() == 0))
+						continue;
+					//if (item.Code == ConfigCode.IgnoreWarningFiles)
+					//{
+					//    List<string> files = item.GetValue<List<string>>();
+					//    foreach (string filename in files)
+					//        writer.WriteLine(item.Text + ":" + filename.ToString());
+					//    continue;
+					//}
+					writer.WriteLine(item.ToString());
+				}
+			}
+			catch (Exception)
+			{
+				return false;
+			}
+			finally
+			{
+				if (writer != null)
+					writer.Close();
+			}
+			return true;
+		}
+
+        public bool ReLoadConfig()
+        {
+            //_fixed.configの中身が変わった場合、非固定になったものが保持されてしまうので、ここで一旦すべて解除
+            foreach (AConfigItem item in configArray)
+            {
+                if (item == null)
+                    continue;
+                if (item.Fixed)
+                    item.Fixed = false;
+            }
+            LoadConfig();
+            return true;
+        }
+
+		public bool LoadConfig()
+		{
+			Config.ClearFont();
+			string defaultConfigPath = Program.CsvDir + "_default.config";
+			string fixedConfigPath = Program.CsvDir + "_fixed.config";
+			if(!File.Exists(defaultConfigPath))
+				defaultConfigPath = Program.CsvDir + "default.config";
+			if (!File.Exists(fixedConfigPath))
+				fixedConfigPath = Program.CsvDir + "fixed.config";
+
+			loadConfig(defaultConfigPath, false);
+			loadConfig(configPath, false);
+			loadConfig(fixedConfigPath, true);
+			
+			Config.SetConfig(this);
+			bool needSave = false;
+			if (!File.Exists(configPath))
+				needSave = true;
+			if (Config.CheckUpdate())
+			{
+				GetItem(ConfigCode.LastKey).SetValue(Config.LastKey);
+				needSave = true;
+			}
+			if (needSave)
+				SaveConfig();
+            return true;
+		}
+
+		private bool loadConfig(string confPath, bool fix)
+		{
+			if (!File.Exists(confPath))
+				return false;
+			EraStreamReader eReader = new EraStreamReader(false);
+			if (!eReader.Open(confPath))
+				return false;
+			ScriptPosition pos = null;
+			try
+			{
+				string line = null;
+				//bool defineIgnoreWarningFiles = false;
+				while ((line = eReader.ReadLine()) != null)
+				{
+					if ((line.Length == 0) || (line[0] == ';'))
+						continue;
+					pos = new ScriptPosition(eReader.Filename, eReader.LineNo, line);
+					string[] tokens = line.Split(':');
+					if (tokens.Length < 2)
+						continue;
+					AConfigItem item = GetConfigItem(tokens[0].Trim());
+					if (item != null)
+					{
+						//1806beta001 CompatiDRAWLINEの廃止、CompatiLinefeedAs1739へ移行
+						if(item.Code == ConfigCode.CompatiDRAWLINE)
+						{
+							item = GetConfigItem(ConfigCode.CompatiLinefeedAs1739);
+						}
+						//if ((item.Code == ConfigCode.IgnoreWarningFiles))
+						//{ 
+						//    if (!defineIgnoreWarningFiles)
+						//        (item.GetValue<List<string>>()).Clear();
+						//    defineIgnoreWarningFiles = true;
+						//    if ((item.Fixed) && (fix))
+						//        item.Fixed = false;
+						//}
+						
+						if (item.Code == ConfigCode.TextEditor)
+						{
+							//パスの関係上tokens[2]は使わないといけない
+							if (tokens.Length > 2)
+							{
+								if (tokens[2].StartsWith("\\"))
+									tokens[1] += ":" + tokens[2];
+								if (tokens.Length > 3)
+								{
+									for (int i = 3; i < tokens.Length; i++)
+									{
+										tokens[1] += ":" + tokens[i];
+									}
+								}
+							}
+						}
+						if (item.Code == ConfigCode.EditorArgument)
+						{
+							//半角スペースを要求する引数が必要なエディタがあるので別処理で
+							((ConfigItem<string>)item).Value = tokens[1];
+							continue;
+						}
+                        if (item.Code == ConfigCode.MaxLog)
+                        {
+                            //解析モード時はここを上書きして十分な長さを確保する
+                            tokens[1] = "10000";
+                        }
+						if ((item.TryParse(tokens[1])) && (fix))
+							item.Fixed = true;
+					}
+#if DEBUG
+					//else
+					//	throw new Exception("コンフィグファイルが変");
+#endif
+				}
+			}
+			catch (EmueraException ee)
+			{
+				ParserMediator.ConfigWarn(ee.Message, pos, 1, null);
+			}
+			catch (Exception exc)
+			{
+				ParserMediator.ConfigWarn(exc.GetType() + ":" + exc.Message, pos, 1, exc.StackTrace);
+			}
+			finally { eReader.Dispose(); }
+			return true;
+		}
+
+#region replace
+		// 1.52a改変部分 (単位の差し替えおよび前置、後置のためのコンフィグ処理)
+		public void LoadReplaceFile(string filename)
+		{
+			EraStreamReader eReader = new EraStreamReader(false);
+			if (!eReader.Open(filename))
+				return;
+			ScriptPosition pos = null;
+			try
+			{
+				string line = null;
+				while ((line = eReader.ReadLine()) != null)
+				{
+					if ((line.Length == 0) || (line[0] == ';'))
+						continue;
+					pos = new ScriptPosition(eReader.Filename, eReader.LineNo, line);
+                    string[] tokens = line.Split(',', ':');
+					if (tokens.Length < 2)
+						continue;
+                    string itemName = tokens[0].Trim();
+                    tokens[1] = line.Substring(tokens[0].Length + 1);
+                    if (string.IsNullOrEmpty(tokens[1].Trim()))
+                        continue;
+                    AConfigItem item = GetReplaceItem(itemName);
+                    if (item != null)
+                        item.TryParse(tokens[1]);
+				}
+			}
+			catch (EmueraException ee)
+			{
+				ParserMediator.Warn(ee.Message, pos, 1);
+			}
+			catch (Exception exc)
+			{
+				ParserMediator.Warn(exc.GetType() + ":" + exc.Message, pos, 1, exc.StackTrace);
+			}
+			finally { eReader.Dispose(); }
+		}
+
+#endregion 
+
+#region debug
+
+
+		public bool SaveDebugConfig()
+		{
+			StreamWriter writer = null;
+			try
+			{
+				writer = new StreamWriter(configdebugPath, false, Config.Encode);
+				for (int i = 0; i < debugArray.Length; i++)
+				{
+					AConfigItem item = debugArray[i];
+					if (item == null)
+						continue;
+					writer.WriteLine(item.ToString());
+				}
+			}
+			catch (Exception)
+			{
+				return false;
+			}
+			finally
+			{
+				if (writer != null)
+					writer.Close();
+			}
+			return true;
+		}
+		
+		public bool LoadDebugConfig()
+		{
+			if (!File.Exists(configdebugPath))
+				goto err;
+			EraStreamReader eReader = new EraStreamReader(false);
+			if (!eReader.Open(configdebugPath))
+				goto err;
+			ScriptPosition pos = null;
+			try
+			{
+				string line = null;
+				while ((line = eReader.ReadLine()) != null)
+				{
+					if ((line.Length == 0) || (line[0] == ';'))
+						continue;
+					pos = new ScriptPosition(eReader.Filename, eReader.LineNo, line);
+					string[] tokens = line.Split(':');
+					if (tokens.Length < 2)
+						continue;
+					AConfigItem item = GetDebugItem(tokens[0].Trim());
+					if (item != null)
+					{
+						item.TryParse(tokens[1]);
+					}
+#if DEBUG
+					//else
+					//	throw new Exception("コンフィグファイルが変");
+#endif
+				}
+			}
+			catch (EmueraException ee)
+			{
+				ParserMediator.ConfigWarn(ee.Message, pos, 1, null);
+				goto err;
+			}
+			catch (Exception exc)
+			{
+				ParserMediator.ConfigWarn(exc.GetType() + ":" + exc.Message, pos, 1, exc.StackTrace);
+				goto err;
+			}
+			finally { eReader.Dispose(); }
+			Config.SetDebugConfig(this);
+            return true;
+		err:
+			Config.SetDebugConfig(this);
+			return false;
+		}
+
+#endregion
+	}
+}

+ 295 - 0
NTERA/Game/Config/ConfigItem.cs

@@ -0,0 +1,295 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera
+{
+	internal abstract class AConfigItem
+	{
+		public AConfigItem(ConfigCode code, string text)
+		{
+			Code = code;
+			Name = code.ToString();
+			Text = text;
+		}
+
+		public static ConfigItem<T> Copy<T>(ConfigItem<T> other)
+		{
+			if(other == null)
+				return null;
+			ConfigItem<T> ret = new ConfigItem<T>(other.Code, other.Text, other.Value);
+			ret.Fixed = other.Fixed;
+			return ret;
+		}
+
+		public abstract void CopyTo(AConfigItem other);
+		public abstract bool TryParse(string tokens);
+		public abstract void SetValue<U>(U p);
+		public abstract U GetValue<U>();
+		public abstract string ValueToString();
+		public readonly ConfigCode Code;
+		public readonly string Name;
+		public readonly string Text;
+		public bool Fixed;
+	}
+	
+	internal sealed class ConfigItem<T> : AConfigItem
+	{
+		public ConfigItem(ConfigCode code,string text, T t):base(code, text)
+		{
+			val = t;
+		}
+		private T val;
+		public T Value
+		{
+			get => val;
+			set
+			{
+				if(Fixed)
+					return;
+				val = value;
+			}
+		}
+
+		public override void CopyTo(AConfigItem other)
+		{
+
+			ConfigItem<T> item = ((ConfigItem<T>)other);
+			item.Fixed = false;
+			item.Value = Value;
+			item.Fixed = Fixed;
+		}
+
+		public override void SetValue<U>(U p)
+		{
+			//if (this is ConfigItem<U>)
+				((ConfigItem<U>)(AConfigItem)this).Value = p;
+            //else
+            //    throw new ExeEE("型が一致しない");
+		}
+
+		public override U GetValue<U>()
+		{
+            ////if (this is ConfigItem<U>)
+				return ((ConfigItem<U>)(AConfigItem)this).Value;
+			//throw new ExeEE("型が一致しない");
+		}
+
+		public override string ValueToString()
+		{
+			if(this is ConfigItem<bool>)
+			{
+				//ConfigItem<T>をConfigItem<bool>に直接キャストすることはできない
+				bool b = ((ConfigItem<bool>)(AConfigItem)this).Value;
+				if (b)
+					return "YES";
+				return "NO";
+			}
+			if (this is ConfigItem<Color>)
+			{
+				Color c = ((ConfigItem<Color>)(AConfigItem)this).Value;
+				return string.Format("{0},{1},{2}", c.R, c.G, c.B);
+			}
+			return val.ToString();
+		}
+		
+		
+		public override string ToString()
+		{
+			return Text + ":" + ValueToString();
+		}
+
+
+
+		/// ジェネリック化大失敗。なんかうまい方法ないかな~
+		public override bool TryParse(string param)
+		{
+			bool ret = false;
+			if ((param == null) || (param.Length == 0))
+				return false;
+			if(Fixed)
+				return false;
+			string str = param.Trim();
+			if (this is ConfigItem<bool>)
+			{
+				bool b = false;
+				ret = tryStringToBool(str, ref b);
+				if (ret)//ConfigItem<T>をConfigItem<bool>に直接キャストすることはできない
+					((ConfigItem<bool>)(AConfigItem)this).Value = b;
+			}
+			else if (this is ConfigItem<Color>)
+			{
+				Color c;
+				ret = tryStringsToColor(str, out c);
+				if (ret)
+					((ConfigItem<Color>)(AConfigItem)this).Value = c;
+                else
+                    throw new CodeEE("Value can not be recognized as Color specifier");
+            }
+			else if (this is ConfigItem<char>)
+			{
+				char c;
+				ret = char.TryParse(str, out c);
+				if (ret)
+					((ConfigItem<char>)(AConfigItem)this).Value = c;
+			}
+			else if (this is ConfigItem<Int32>)
+			{
+				Int32 i;
+				ret = Int32.TryParse(str, out i);
+				if (ret)
+					((ConfigItem<Int32>)(AConfigItem)this).Value = i;
+                else
+                    throw new CodeEE("Numeric config item contains non-numeric characters");
+            }
+			else if (this is ConfigItem<Int64>)
+			{
+				Int64 i;
+				ret = Int64.TryParse(str, out i);
+                if (ret)
+                    ((ConfigItem<Int64>)(AConfigItem)this).Value = i;
+                else
+                    throw new CodeEE("Numeric config item contains non-numeric characters");
+			}
+            else if (this is ConfigItem<List<Int64>>)
+            {
+                ((ConfigItem<List<Int64>>)(AConfigItem)this).Value.Clear();
+                Int64 i;
+                string[] strs = str.Split('/');
+                foreach (string st in strs)
+                {
+                    ret = Int64.TryParse(st.Trim(), out i);
+                    if (ret)
+                        ((ConfigItem<List<Int64>>)(AConfigItem)this).Value.Add(i);
+                    else
+                    {
+                        throw new CodeEE("Numeric config item contains non-numeric characters");
+                    }
+                }
+            }
+            else if (this is ConfigItem<string>)
+            {
+                ret = true;
+                ((ConfigItem<string>)(AConfigItem)this).Value = str;
+            }
+            else if (this is ConfigItem<List<string>>)
+            {
+                ret = true;
+                ((ConfigItem<List<string>>)(AConfigItem)this).Value.Add(str);
+            }
+            else if (this is ConfigItem<TextDrawingMode>)
+            {
+                str = str.ToUpper();
+                ret = Enum.IsDefined(typeof(TextDrawingMode), str);
+                if (ret)
+                {
+                    ((ConfigItem<TextDrawingMode>)(AConfigItem)this).Value
+                     = (TextDrawingMode)Enum.Parse(typeof(TextDrawingMode), str);
+                }
+                else
+                    throw new CodeEE("Invalid specification");
+            }
+            else if (this is ConfigItem<ReduceArgumentOnLoadFlag>)
+            {
+                str = str.ToUpper();
+                ret = Enum.IsDefined(typeof(ReduceArgumentOnLoadFlag), str);
+                if (ret)
+                {
+                    ((ConfigItem<ReduceArgumentOnLoadFlag>)(AConfigItem)this).Value
+                     = (ReduceArgumentOnLoadFlag)Enum.Parse(typeof(ReduceArgumentOnLoadFlag), str);
+                }
+                else
+                    throw new CodeEE("Invalid specification");
+            }
+            else if (this is ConfigItem<DisplayWarningFlag>)
+            {
+                str = str.ToUpper();
+                ret = Enum.IsDefined(typeof(DisplayWarningFlag), str);
+                if (ret)
+                {
+                    ((ConfigItem<DisplayWarningFlag>)(AConfigItem)this).Value
+                     = (DisplayWarningFlag)Enum.Parse(typeof(DisplayWarningFlag), str);
+                }
+                else
+                    throw new CodeEE("Invalid specification");
+            }
+            else if (this is ConfigItem<UseLanguage>)
+            {
+                str = str.ToUpper();
+                ret = Enum.IsDefined(typeof(UseLanguage), str);
+                if (ret)
+                {
+                    ((ConfigItem<UseLanguage>)(AConfigItem)this).Value
+                        = (UseLanguage)Enum.Parse(typeof(UseLanguage), str);
+                }
+                else
+                    throw new CodeEE("Invalid specification");
+            }
+            else if (this is ConfigItem<TextEditorType>)
+            {
+                str = str.ToUpper();
+                ret = Enum.IsDefined(typeof(TextEditorType), str);
+                if (ret)
+                {
+                    ((ConfigItem<TextEditorType>)(AConfigItem)this).Value
+                        = (TextEditorType)Enum.Parse(typeof(TextEditorType), str);
+                }
+                else
+                    throw new CodeEE("Invalid specification");
+            }
+            //else
+            //    throw new ExeEE("型不明なコンフィグ");
+			return ret;
+		}
+		
+		
+
+		private bool tryStringToBool(string arg, ref bool p)
+		{
+			if (arg == null)
+				return false;
+			string str = arg.Trim();
+			int i = 0;
+			if (Int32.TryParse(str, out i))
+			{
+				p = (i != 0);
+				return true;
+			}
+			if (str.Equals("NO", StringComparison.CurrentCultureIgnoreCase)
+				|| str.Equals("FALSE", StringComparison.CurrentCultureIgnoreCase)
+				|| str.Equals("後", StringComparison.CurrentCultureIgnoreCase))//"単位の位置"用
+			{
+				p = false;
+				return true;
+			}
+			if (str.Equals("YES", StringComparison.CurrentCultureIgnoreCase)
+				|| str.Equals("TRUE", StringComparison.CurrentCultureIgnoreCase)
+				|| str.Equals("前", StringComparison.CurrentCultureIgnoreCase))
+			{
+				p = true;
+				return true;
+			}
+			throw new CodeEE("Invalid specification");
+		}
+
+		private bool tryStringsToColor(string str, out Color c)
+		{
+			string[] tokens = str.Split(',');
+			c = Color.Black;
+			int r, g, b;
+			if (tokens.Length < 3)
+				return false;
+			if (!Int32.TryParse(tokens[0].Trim(), out r) || (r < 0) || (r > 255))
+				return false;
+			if (!Int32.TryParse(tokens[1].Trim(), out g) || (g < 0) || (g > 255))
+				return false;
+			if (!Int32.TryParse(tokens[2].Trim(), out b) || (b < 0) || (b > 255))
+				return false;
+			c = Color.FromArgb(r, g, b);
+			return true;
+		}
+	}
+}
+
+

+ 129 - 0
NTERA/Game/Config/KeyMacro.cs

@@ -0,0 +1,129 @@
+
+using System;
+using System.IO;
+using MinorShift.Emuera.Sub;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera
+{
+	internal static class KeyMacro
+	{
+		static readonly string macroPath = Program.ExeDir + "macro.txt";
+		public const string gID = "グループ";
+		public const int MaxGroup = 10;
+		public const int MaxFkey = 12;
+		public const int MaxMacro = MaxFkey * MaxGroup;
+		/// <summary>
+		/// マクロの内容
+		/// </summary>
+		static string[] macro = new string[MaxMacro];
+		/// <summary>
+		/// マクロキー
+		/// </summary>
+		static string[] macroName = new string[MaxMacro];
+		static string[] groupName = new string[MaxGroup];
+		static bool isMacroChanged;
+		static KeyMacro()
+		{
+			for (int g = 0; g < MaxGroup; g++)
+			{
+				groupName[g] = "マクログループ" + g + "に設定";
+				for (int f = 0; f < MaxFkey; f++)
+				{
+					int i = f + g * MaxFkey;
+					macro[i] = "";
+					if (g == 0)
+						macroName[i] = "マクロキーF" + (f + 1) + ":";
+					else
+						macroName[i] = "G" + g + ":マクロキーF" + (f + 1) + ":";
+
+				}
+			}
+		}
+
+		public static bool SaveMacro()
+		{
+			if (!isMacroChanged)
+				return true;
+			StreamWriter writer = null;
+
+			try
+			{
+				writer = new StreamWriter(macroPath, false, Config.Encode);
+				for (int g = 0; g < MaxGroup; g++)
+				{
+					writer.WriteLine(gID + g + ":" + groupName[g]);
+				}
+				for (int i = 0; i < MaxMacro; i++)
+				{
+					writer.WriteLine(macroName[i] + macro[i]);
+				}
+			}
+			catch (Exception)
+			{
+				return false;
+			}
+			finally
+			{
+				if (writer != null)
+					writer.Close();
+			}
+			return true;
+		}
+
+		public static void LoadMacroFile(string filename)
+		{
+			EraStreamReader eReader = new EraStreamReader(false);
+			if (!eReader.Open(filename))
+				return;
+			try
+			{
+				string line = null;
+				while ((line = eReader.ReadLine()) != null)
+				{
+					if ((line.Length == 0) || (line[0] == ';'))
+						continue;
+					if (line.StartsWith(gID))
+					{
+						if (line.Length < gID.Length + 4)
+							continue;
+						int num = line[gID.Length] - '0';
+						if (num < 0 || num > 9)
+							continue;
+						if (line[gID.Length + 1] != ':')
+							continue;
+						groupName[num] = line.Substring(gID.Length + 2);
+					}
+					for (int i = 0; i < MaxMacro; i++)
+					{
+						if (line.StartsWith(macroName[i]))
+						{
+							macro[i] = line.Substring(macroName[i].Length);
+							break;
+						}
+					}
+				}
+			}
+			catch {
+			}
+			finally { eReader.Dispose(); }
+		}
+
+		public static void SetMacro(int FkeyNum, int groupNum, string macroStr)
+		{
+			isMacroChanged = true;
+			macro[FkeyNum + groupNum * MaxFkey] = macroStr;
+		}
+
+		public static string GetMacro(int FkeyNum, int groupNum)
+		{
+			return macro[FkeyNum + groupNum * MaxFkey];
+		}
+
+		public static string GetGroupName(int groupNum)
+		{
+			return groupName[groupNum];
+		}
+	}
+
+}

+ 19 - 0
NTERA/Game/Content/AContentFile.cs

@@ -0,0 +1,19 @@
+using System;
+
+namespace MinorShift.Emuera.Content
+{
+	abstract class AContentFile : IDisposable
+	{
+		public AContentFile(string name, string path)
+		{
+			Name = name;
+			Filepath = path;
+		}
+		public readonly string Name;
+		public readonly string Filepath;
+		protected bool Loaded = false;
+		public bool Enabled { get; protected set; }
+
+		public abstract void Dispose();
+	}
+}

+ 9 - 0
NTERA/Game/Content/AContentItem.cs

@@ -0,0 +1,9 @@
+namespace MinorShift.Emuera.Content
+{
+	abstract class AContentItem
+	{
+		protected AContentItem(string name) { Name = name; }
+		public readonly string Name;
+		public bool Enabled = false;
+	}
+}

+ 122 - 0
NTERA/Game/Content/AppContents.cs

@@ -0,0 +1,122 @@
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using MinorShift.Emuera.Sub;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera.Content
+{
+	static class AppContents
+	{
+		public static T GetContent<T>(string name) where T : AContentItem
+		{
+			if (name == null)
+				return null;
+			name = name.ToUpper();
+			if (!itemDic.ContainsKey(name))
+				return null;
+			return itemDic[name] as T;
+		}
+
+		public static void LoadContents()
+		{
+			if (!Directory.Exists(Program.ContentDir))
+				return;
+			try
+			{
+				List<string> bmpfilelist = new List<string>();
+				bmpfilelist.AddRange(Directory.GetFiles(Program.ContentDir, "*.png", SearchOption.TopDirectoryOnly));
+				bmpfilelist.AddRange(Directory.GetFiles(Program.ContentDir, "*.bmp", SearchOption.TopDirectoryOnly));
+				bmpfilelist.AddRange(Directory.GetFiles(Program.ContentDir, "*.jpg", SearchOption.TopDirectoryOnly));
+				bmpfilelist.AddRange(Directory.GetFiles(Program.ContentDir, "*.gif", SearchOption.TopDirectoryOnly));
+				foreach (var filename in bmpfilelist)
+				{//リスト化のみ。Loadはまだ
+					string name = Path.GetFileName(filename).ToUpper();
+					resourceDic.Add(name, new BaseImage(name, filename));
+				}
+				string[] csvFiles = Directory.GetFiles(Program.ContentDir, "*.csv", SearchOption.TopDirectoryOnly);
+				foreach (var filename in csvFiles)
+				{
+					string[] lines = File.ReadAllLines(filename, Config.Encode);
+					foreach (var line in lines)
+					{
+						if (line.Length == 0)
+							continue;
+						string str = line.Trim();
+						if (str.Length == 0 || str.StartsWith(";"))
+							continue;
+						string[] tokens = str.Split(',');
+						AContentItem item = CreateFromCsv(tokens);
+						if (item != null && !itemDic.ContainsKey(item.Name))
+							itemDic.Add(item.Name, item);
+					}
+				}
+			}
+			catch
+			{
+				throw new CodeEE("An error occurred while loading the resource file");
+			}
+		}
+
+		public static void UnloadContents()
+		{
+			foreach (var img in resourceDic.Values)
+				img.Dispose();
+			resourceDic.Clear();
+			itemDic.Clear();
+		}
+
+		private static AContentItem CreateFromCsv(string[] tokens)
+		{
+			if(tokens.Length < 2)
+				return null;
+			string name = tokens[0].Trim().ToUpper();
+			string parentName = tokens[1].ToUpper();
+			if (name.Length == 0 || parentName.Length == 0)
+				return null;
+			if (!resourceDic.ContainsKey(parentName))
+				return null;
+			AContentFile parent = resourceDic[parentName];
+			if(parent is BaseImage)
+			{
+				BaseImage parentImage = parent as BaseImage;
+				parentImage.Load(Config.TextDrawingMode == TextDrawingMode.WINAPI);
+				if (!parentImage.Enabled)
+						return null;
+				Rectangle rect = new Rectangle(new Point(0, 0), parentImage.Bitmap.Size);
+				bool noresize = false;
+				if(tokens.Length >= 6)
+				{
+					int[] rectValue = new int[4];
+					bool sccs = true;
+					for (int i = 0; i < 4; i++)
+						sccs &= int.TryParse(tokens[i + 2], out rectValue[i]);
+					if (sccs)
+						rect = new Rectangle(rectValue[0], rectValue[1], rectValue[2], rectValue[3]);
+					if(tokens.Length >= 7)
+					{
+						string[] keywordTokens = tokens[6].Split('|');
+						foreach(string keyword in keywordTokens)
+						{
+							switch(keyword.Trim().ToUpper())
+							{
+								case "NORESIZE":
+									throw new NotImplCodeEE();
+									noresize = true;
+									break;
+							}
+						}
+					}
+				}
+				CroppedImage image = new CroppedImage(name, parentImage, rect, noresize);
+				return image;
+			}
+			return null;
+		}
+
+
+		static Dictionary<string, AContentFile> resourceDic = new Dictionary<string, AContentFile>();
+		static Dictionary<string, AContentItem> itemDic = new Dictionary<string, AContentItem>();
+
+	}
+}

+ 56 - 0
NTERA/Game/Content/BaseImage.cs

@@ -0,0 +1,56 @@
+using System;
+using System.Drawing;
+using MinorShift._Library;
+
+namespace MinorShift.Emuera.Content
+{
+
+	internal sealed class BaseImage : AContentFile
+	{
+		public BaseImage(string name, string path)
+			: base(name, path)
+		{ }
+		public Bitmap Bitmap;
+		Graphics g;
+		public void Load(bool useGDI)
+		{
+			if (Loaded)
+				return;
+			try
+			{
+				Bitmap = new Bitmap(Filepath);
+				//if (useGDI)
+				//{
+				//	hBitmap = Bitmap.GetHbitmap();
+				//	g = Graphics.FromImage(Bitmap);
+				//	GDIhDC = g.GetHdc();
+				//	hDefaultImg = GDI.SelectObject(GDIhDC, hBitmap);
+				//}
+				Loaded = true;
+				Enabled = true;
+			}
+			catch
+			{
+				return;
+			}
+		}
+
+		public override void Dispose()
+		{
+			if (Bitmap == null)
+				return;
+			if (g != null)
+			{
+				g.Dispose();
+				g = null;
+			}
+			Bitmap.Dispose();
+			Bitmap = null;
+		}
+
+        ~BaseImage()
+        {
+            Dispose();
+        }
+	}
+}

+ 21 - 0
NTERA/Game/Content/CroppedImage.cs

@@ -0,0 +1,21 @@
+using System.Drawing;
+
+namespace MinorShift.Emuera.Content
+{
+	internal sealed class CroppedImage : AContentItem
+	{
+		public CroppedImage(string name, BaseImage image, Rectangle rect, bool noresize) : base(name)
+		{
+			BaseImage = image;
+			Rectangle = rect;
+			if (image != null)
+				Enabled = image.Enabled;
+			if (rect.Width <= 0 || rect.Height <= 0)
+				Enabled = false;
+			NoResize = noresize;
+		}
+		public readonly BaseImage BaseImage;
+		public readonly Rectangle Rectangle;
+		public readonly bool NoResize;
+	}
+}

+ 43 - 0
NTERA/Game/Display/AConsoleDisplayPart.cs

@@ -0,0 +1,43 @@
+using System.Drawing;
+using MinorShift.Emuera;
+
+namespace NTERA.Game.Display
+{
+	/// <summary>
+	/// 描画の最小単位
+	/// </summary>
+	public abstract class AConsoleDisplayPart
+	{
+		public bool Error { get; protected set; }
+
+		public string Str { get; protected set; }
+		public string AltText { get; protected set; }
+		public int PointX { get; set; }
+		public float XsubPixel { get; set; }
+		public float WidthF { get; set; }
+		public int Width { get; set; }
+		public virtual int Top => 0;
+		public virtual int Bottom => Config.FontSize;
+		public abstract bool CanDivide { get; }
+		
+		public abstract void DrawTo(Graphics graph, int pointY, bool isSelecting, bool isBackLog, TextDrawingMode mode);
+
+		public abstract void SetWidth(StringMeasure sm, float subPixel);
+		public override string ToString()
+		{
+			if (Str == null)
+				return "";
+			return Str;
+		}
+	}
+
+	/// <summary>
+	/// 色つき
+	/// </summary>
+	abstract class AConsoleColoredPart : AConsoleDisplayPart
+	{
+		protected Color Color { get; set; }
+		protected Color ButtonColor { get; set; }
+		protected bool colorChanged;
+	}
+}

+ 266 - 0
NTERA/Game/Display/ButtonStringCreator.cs

@@ -0,0 +1,266 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+using MinorShift.Emuera.Sub;
+
+namespace NTERA.Game.Display
+{
+	internal sealed class ButtonPrimitive
+	{
+		public string Str = "";
+		public Int64 Input;
+		public bool CanSelect;
+		public override string ToString()
+		{
+			return Str;
+		}
+	}
+
+	internal static class ButtonStringCreator
+	{
+		public static List<string> Split(string printBuffer)
+		{
+			List<ButtonPrimitive> list = syn(printBuffer);
+			List<string> ret = new List<string>();
+			foreach(ButtonPrimitive p in list)
+				ret.Add(p.Str);
+			return ret;
+		}
+		public static List<ButtonPrimitive> SplitButton(string printBuffer)
+		{
+			return syn(printBuffer);
+		}
+
+		private static List<ButtonPrimitive> syn(string printBuffer)
+		{
+			string printString = printBuffer;
+			List<ButtonPrimitive> ret = new List<ButtonPrimitive>();
+			if (printString.Length == 0)
+				goto nonButton;
+			List<string> strs = null;
+			if ((!printString.Contains("[")) || (!printString.Contains("]")))
+				goto nonButton;
+			strs = lex(new StringStream(printString));
+			if (strs == null)
+				goto nonButton;
+			bool beforeButton = false;//最初のボタン("[1]"とか)より前にテキストがある
+			bool afterButton = false;//最後のボタン("[1]"とか)より後にテキストがある
+			int buttonCount = 0;
+			Int64 inpL = 0;
+			for (int i = 0; i < strs.Count; i++)
+			{
+				if (strs[i].Length == 0)
+					continue;
+				char c = strs[i][0];
+				if (LexicalAnalyzer.IsWhiteSpace(c))
+				{//ただの空白
+				}
+				//数値以外はボタン化しない方向にした。
+				//else if ((c == '[') && (!isSymbols(strArray[i])))
+				else if (isButtonCore(strs[i], ref inpL))
+				{//[]で囲まれた文字列。選択肢の核となるかどうかはこの段階では判定しない。
+					buttonCount++;
+					afterButton = false;
+				}
+				else
+				{//選択肢の説明になるかもしれない文字列
+                    afterButton = true;
+					if (buttonCount == 0)
+						beforeButton = true;
+				}
+			}
+			if (buttonCount <= 1)
+			{
+				ButtonPrimitive button = new ButtonPrimitive();
+				button.Str = printBuffer;
+				button.CanSelect = (buttonCount >= 1);
+				button.Input = inpL;
+				ret.Add(button);
+				return ret;
+			}
+			buttonCount = 0;
+			bool alignmentRight = !beforeButton && afterButton;//説明はボタンの右固定
+			bool alignmentLeft = beforeButton && !afterButton;//説明はボタンの左固定
+			bool alignmentEtc = !alignmentRight && !alignmentLeft;//臨機応変に
+			bool canSelect = false;
+			Int64 input = 0;
+
+			int state = 0;
+			StringBuilder buffer = new StringBuilder();
+			VoidMethod reduce = delegate
+			{
+				if (buffer.Length == 0)
+					return;
+				ButtonPrimitive button = new ButtonPrimitive();
+				button.Str = buffer.ToString();
+				button.CanSelect = canSelect;
+				button.Input = input;
+				ret.Add(button);
+				buffer.Remove(0, buffer.Length);
+				canSelect = false;
+				input = 0;
+			};
+			for (int i = 0; i < strs.Count; i++)
+			{
+				if (strs[i].Length == 0)
+					continue;
+				char c = strs[i][0];
+				if (LexicalAnalyzer.IsWhiteSpace(c))
+				{//ただの空白
+					if (((state & 3) == 3) && (alignmentEtc) && (strs[i].Length >= 2))
+					{//核と説明を含んだものが完成していればボタン生成。
+						//一文字以下のスペースはキニシナイ。キャラ購入画面対策
+                        reduce();
+						buffer.Append(strs[i]);
+						state = 0;
+					}
+					else
+					{
+						buffer.Append(strs[i]);
+					}
+					continue;
+				}
+				if(isButtonCore(strs[i], ref inpL))
+				{
+					buttonCount++;
+					if (((state & 1) == 1) || alignmentRight)
+					{//bufferが既に核を含んでいる、又は強制的に右配置
+						reduce();
+						buffer.Append(strs[i]);
+						input = inpL;
+						canSelect = true;
+						state = 1;
+					}//((state & 2) == 2) || 
+					else if (alignmentLeft)
+					{//bufferが説明を含んでいる、又は強制的に左配置
+						buffer.Append(strs[i]);
+						input = inpL;
+						canSelect = true;
+						reduce();
+						state = 0;
+					}
+					else
+					{//bufferが空または空白文字列
+						buffer.Append(strs[i]);
+						input = inpL;
+						canSelect = true;
+						state = 1;
+					}
+					continue;
+				}
+				//else
+				//{//選択肢の説明になるかもしれない文字列
+					
+					buffer.Append(strs[i]);
+					state |= 2;
+				//}
+				
+			};
+			reduce();
+			return ret;
+		nonButton:
+			ret = new List<ButtonPrimitive>();
+			ButtonPrimitive singleButton = new ButtonPrimitive();
+			singleButton.Str = printString;
+			ret.Add(singleButton);
+			return ret;
+		}
+		static readonly Regex numReg = new Regex(@"\[\s*([0][xXbB])?[+-]?[0-9]+([eEpP][0-9]+)?\s*\]");
+
+		/// <summary>
+		/// []付き文字列が数値的であるかどうかを調べる
+		/// </summary>
+		/// <param name="str"></param>
+		/// <returns></returns>
+		private static bool isNumericWord(string str)
+		{
+			return numReg.IsMatch(str);
+		}
+
+		/// <summary>
+		/// ボタンの核になるかどうか。とりあえずは整数のみ。
+		/// try-catchを利用するので少し重い。
+		/// </summary>
+		/// <param name="str"></param>
+		/// <param name="input"></param>
+		/// <returns></returns>
+		private static bool isButtonCore(string str, ref long input)
+		{
+			if((str == null)||(str.Length < 3)||(str[0] != '[')||(str[str.Length-1] != ']'))
+				return false;
+			if (!isNumericWord(str))
+				return false;
+			string buttonStr = str.Substring(1, str.Length - 2);
+			StringStream stInt = new StringStream(buttonStr);
+			LexicalAnalyzer.SkipAllSpace(stInt);
+			try
+			{
+				input = LexicalAnalyzer.ReadInt64(stInt, false);
+			}
+			catch
+			{
+				return false; 
+			}
+			return true;
+		}
+
+
+		delegate void VoidMethod();
+
+		/// <summary>
+		/// 字句分割
+		/// "[1] あ [2] いうえ "を"[1]"," ", "あ"," ","[2]"," ","いうえ"," "に分割
+		/// </summary>
+		/// <param name="st"></param>
+		/// <returns></returns>
+		private static List<string> lex(StringStream st)
+		{
+			List<string> strs = new List<string>();
+			int state = 0;
+			int startIndex = 0;
+			VoidMethod reduce = delegate
+			{
+				if (st.CurrentPosition == startIndex)
+					return;
+				int length = st.CurrentPosition - startIndex;
+				strs.Add(st.Substring(startIndex, length));
+				startIndex = st.CurrentPosition;
+			};
+			while (!st.EOS)
+			{
+				if (st.Current == '[')
+				{
+					if (state == 1)//"["内部
+						goto unanalyzable;
+					reduce();
+					state = 1;
+					st.ShiftNext();
+				}
+				else if (st.Current == ']')
+				{
+					if (state != 1)//"["外部
+						goto unanalyzable;
+					st.ShiftNext();
+					reduce();
+					state = 0;
+				}
+				else if ((state == 0) && (LexicalAnalyzer.IsWhiteSpace(st.Current)))
+				{
+					reduce();
+					LexicalAnalyzer.SkipAllSpace(st);
+					reduce();
+				}
+				else
+				{
+					st.ShiftNext();
+				}
+			}
+			reduce();
+			return strs;
+		unanalyzable:
+			return null;
+		}
+
+	}
+}

+ 240 - 0
NTERA/Game/Display/ConsoleButtonString.cs

@@ -0,0 +1,240 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using MinorShift.Emuera;
+using MinorShift.Emuera.Sub;
+using NTERA.Interop;
+
+namespace NTERA.Game.Display
+{
+	/// <summary>
+	/// ボタン。1つ以上の装飾付文字列(ConsoleStyledString)からなる。
+	/// </summary>
+	public sealed class ConsoleButtonString
+	{
+		public ConsoleButtonString(IConsole console, AConsoleDisplayPart[] strs)
+		{
+			parent = console;
+			strArray = strs;
+			IsButton = false;
+			PointX = -1;
+			Width = -1;
+            ErrPos = null;
+		}
+		public ConsoleButtonString(IConsole console, AConsoleDisplayPart[] strs, Int64 input)
+			:this(console, strs)
+		{
+			Input = input;
+			Inputs = input.ToString();
+			IsButton = true;
+			IsInteger = true;
+			if (console != null)
+			{
+				Generation = parent.NewButtonGeneration;
+				console.UpdateGeneration();
+			}
+            ErrPos = null;
+        }
+		public ConsoleButtonString(IConsole console, AConsoleDisplayPart[] strs, string inputs)
+			: this(console, strs)
+		{
+			Inputs = inputs;
+			IsButton = true;
+			IsInteger = false;
+			if (console != null)
+			{
+				Generation = parent.NewButtonGeneration;
+				console.UpdateGeneration();
+			}
+            ErrPos = null;
+        }
+
+		public ConsoleButtonString(IConsole console, AConsoleDisplayPart[] strs, Int64 input, string inputs)
+			: this(console, strs)
+		{
+			Input = input;
+			Inputs = inputs;
+			IsButton = true;
+			IsInteger = true;
+			if (console != null)
+			{
+				Generation = parent.NewButtonGeneration;
+				console.UpdateGeneration();
+			}
+            ErrPos = null;
+        }
+		public ConsoleButtonString(IConsole console, AConsoleDisplayPart[] strs, string inputs, ScriptPosition pos)
+            : this(console, strs)
+        {
+            Inputs = inputs;
+            IsButton = true;
+            IsInteger = false;
+			if (console != null)
+			{
+				Generation = parent.NewButtonGeneration;
+				console.UpdateGeneration();
+			}
+            ErrPos = pos;
+        }
+
+		AConsoleDisplayPart[] strArray;
+		public AConsoleDisplayPart[] StrArray => strArray;
+		IConsole parent;
+
+		public ConsoleDisplayLine ParentLine { get; set; }
+		public bool IsButton { get; private set; }
+		public bool IsInteger { get; private set; }
+		public Int64 Input { get; private set; }
+		public string Inputs { get; private set; }
+		public int PointX { get; set; }
+		public bool PointXisLocked { get; set; }
+		public int Width { get; set; }
+		public float XsubPixel { get; set; }
+		public Int64 Generation { get; private set; }
+		public ScriptPosition ErrPos { get; set; }
+		public string Title { get; set; }
+
+
+		public int RelativePointX { get; private set; }
+		public void LockPointX(int rel_px)
+		{
+			PointX = rel_px * Config.FontSize / 100;
+			XsubPixel = (rel_px * Config.FontSize / 100.0f) - PointX;
+			PointXisLocked = true;
+			RelativePointX = rel_px;
+		}
+
+		//indexの文字数の前方文字列とindex以降の後方文字列に分割
+		public ConsoleButtonString DivideAt(int divIndex, StringMeasure sm)
+		{
+			if (divIndex <= 0)
+				return null;
+			List<AConsoleDisplayPart> cssListA = new List<AConsoleDisplayPart>();
+			List<AConsoleDisplayPart> cssListB = new List<AConsoleDisplayPart>();
+			int index = 0;
+			int cssIndex = 0;
+			bool b = false;
+			for (cssIndex = 0; cssIndex < strArray.Length; cssIndex++)
+			{
+				if (b)
+				{
+					cssListB.Add(strArray[cssIndex]);
+					continue;
+				}
+				int length = strArray[cssIndex].Str.Length;
+				if (divIndex < index + length)
+				{
+					ConsoleStyledString oldcss = strArray[cssIndex] as ConsoleStyledString;
+					if (oldcss == null || !oldcss.CanDivide)
+						throw new ExeEE("文字列分割異常");
+					ConsoleStyledString newCss = oldcss.DivideAt(divIndex - index, sm);
+					cssListA.Add(oldcss);
+					if (newCss != null)
+						cssListB.Add(newCss);
+					b = true;
+					continue;
+				}
+
+				if (divIndex == index + length)
+				{
+					cssListA.Add(strArray[cssIndex]);
+					b = true;
+					continue;
+				}
+				index += length;
+				cssListA.Add(strArray[cssIndex]);
+			}
+			if ((cssIndex >= strArray.Length) && (cssListB.Count == 0))
+				return null;
+			AConsoleDisplayPart[] cssArrayA = new AConsoleDisplayPart[cssListA.Count];
+			AConsoleDisplayPart[] cssArrayB = new AConsoleDisplayPart[cssListB.Count];
+			cssListA.CopyTo(cssArrayA);
+			cssListB.CopyTo(cssArrayB);
+			strArray = cssArrayA;
+			ConsoleButtonString ret = new ConsoleButtonString(null, cssArrayB);
+			CalcWidth(sm, XsubPixel);
+			ret.CalcWidth(sm,0);
+			CalcPointX(PointX);
+			ret.CalcPointX(PointX + Width);
+			ret.parent = parent;
+			ret.ParentLine = ParentLine;
+			ret.IsButton = IsButton;
+			ret.IsInteger = IsInteger;
+			ret.Input = Input;
+			ret.Inputs = Inputs;
+			ret.Generation = Generation;
+			ret.ErrPos = ErrPos;
+			ret.Title = Title;
+			return ret;
+		}
+
+		public void CalcWidth(StringMeasure sm, float subpixel)
+		{
+			Width = -1;
+			if ((strArray != null) && (strArray.Length > 0))
+			{
+				Width = 0;
+				foreach (AConsoleDisplayPart css in strArray)
+				{
+					if(css.Width <= 0)
+						css.SetWidth(sm,subpixel);
+					Width += css.Width;
+					subpixel = css.XsubPixel;
+				}
+				if (Width <= 0)
+					Width = -1;
+			}
+			XsubPixel = subpixel;
+		}
+
+		/// <summary>
+		/// 先にCalcWidthすること。
+		/// </summary>
+		/// <param name="sm"></param>
+		public void CalcPointX(int pointx)
+		{
+			int px = pointx;
+			if (!PointXisLocked)
+				PointX = px;
+			else
+				px = PointX;
+			for (int i = 0; i < strArray.Length; i++)
+			{
+				strArray[i].PointX = px;
+				px += strArray[i].Width;
+			}
+			if (strArray.Length > 0)
+			{
+				PointX = strArray[0].PointX;
+				Width = strArray[strArray.Length - 1].PointX + strArray[strArray.Length - 1].Width - PointX;
+				//if (Width < 0)
+				//	Width = -1;
+			}
+		}
+
+		internal void ShiftPositionX(int shiftX)
+		{
+			PointX += shiftX;
+			foreach (AConsoleDisplayPart css in strArray)
+				css.PointX += shiftX;
+		}
+
+		public void DrawTo(Graphics graph, int pointY, bool isBackLog, TextDrawingMode mode)
+		{
+			bool isSelecting = (IsButton) && (parent.ButtonIsSelected(this));
+			foreach (AConsoleDisplayPart css in strArray)
+				css.DrawTo(graph, pointY, isSelecting, isBackLog, mode);
+		}
+		
+		public override string ToString()
+		{
+			if (strArray == null)
+				return "";
+			string str = "";
+			foreach (AConsoleDisplayPart css in strArray)
+				str += css.ToString();
+			return str;
+		}
+
+	}
+}

+ 145 - 0
NTERA/Game/Display/ConsoleDisplayLine.cs

@@ -0,0 +1,145 @@
+using System;
+using System.Drawing;
+using System.Reflection;
+using System.Text;
+using MinorShift.Emuera;
+using NTERA.Interop;
+
+namespace NTERA.Game.Display
+{
+	//難読化用属性。enum.ToString()やenum.Parse()を行うなら(Exclude=true)にすること。
+	[Obfuscation(Exclude=false)]
+	internal enum DisplayLineLastState
+	{
+		None = 0,
+		Normal = 1,
+		Selected = 2,
+		BackLog = 3
+	}
+
+    /// <summary>
+    /// Display line. It consists of one or more buttons (ConsoleButtonString)
+    /// </summary>
+    public sealed class ConsoleDisplayLine
+	{
+		
+		//public ConsoleDisplayLine(EmueraConsole parentWindow, ConsoleButtonString[] buttons, bool isLogical, bool temporary)
+		public ConsoleDisplayLine(ConsoleButtonString[] buttons, bool isLogical, bool temporary)
+		{
+			//parent = parentWindow;
+			if (buttons == null)
+			{
+				buttons = new ConsoleButtonString[0];
+				return;
+			}
+			this.buttons = buttons;
+			foreach (ConsoleButtonString button in buttons)
+            {
+                if (button == null)
+                    throw new Exception();
+                button.ParentLine = this;
+            }
+			IsLogicalLine = isLogical;
+			IsTemporary = temporary;
+		}
+		public int LineNo = -1;
+		
+		///論理行の最初となる場合だけtrue。表示の都合で改行された2行目以降はfalse
+		public readonly bool IsLogicalLine = true;
+		public readonly bool IsTemporary;
+		//EmueraConsole parent;
+		ConsoleButtonString[] buttons;
+		DisplayLineAlignment align;
+		public ConsoleButtonString[] Buttons => buttons;
+		public DisplayLineAlignment Align => align;
+		bool aligned;
+		public void SetAlignment(DisplayLineAlignment align)
+		{
+			if (aligned)
+				return;
+			aligned = true;
+			this.align = align;
+			if (buttons.Length == 0)
+				return;
+			//DisplayLineの幅
+			int width = 0;
+			foreach (ConsoleButtonString button in buttons)
+				width += button.Width;
+			//現在位置
+			int pointX = buttons[0].PointX;
+
+			//目標位置
+			int movetoX = 0;
+			if (align == DisplayLineAlignment.LEFT)
+			{
+				//位置固定に対応
+				if (IsLogicalLine)
+					return;
+				movetoX = 0;
+			}
+			else if (align == DisplayLineAlignment.CENTER)
+				movetoX = Config.WindowX / 2 - width / 2;
+			else if (align == DisplayLineAlignment.RIGHT)
+				movetoX = Config.WindowX - width;
+
+			//移動距離
+			int shiftX = movetoX - pointX;
+			if(shiftX != 0)
+				ShiftPositionX(shiftX);
+		}
+
+		public void ShiftPositionX(int shiftX)
+		{
+			foreach (ConsoleButtonString button in buttons)
+				button.ShiftPositionX(shiftX);
+		}
+
+		public void ChangeStr(ConsoleButtonString[] newButtons)
+        {
+            buttons = null;
+			foreach (ConsoleButtonString button in newButtons)
+				button.ParentLine = this;
+			buttons = newButtons;
+        }
+
+		public void Clear(Brush brush, Graphics graph, int pointY)
+		{
+            Rectangle rect = new Rectangle(0, pointY, Config.WindowX, Config.LineHeight);
+			graph.FillRectangle(brush, rect);
+		}
+
+		//public ConsoleButtonString GetPointingButton(int pointX)
+		//{
+		//	////1815 優先順位を逆順にする
+		//	////後から描画されるボタンが優先されるように
+		//	for (int i = 0; i < buttons.Length; i++)
+		//	{
+		//		ConsoleButtonString button = buttons[buttons.Length - i - 1];
+		//		if ((button.PointX <= pointX) && (button.PointX + button.Width >= pointX))
+		//			return button;
+		//	}
+		//	//foreach (ConsoleButtonString button in buttons)
+		//	//{
+		//	//    if ((button.PointX <= pointX) && (button.PointX + button.Width >= pointX))
+		//	//        return button;
+		//	//}
+		//	return null;
+		//}
+
+		public void DrawTo(Graphics graph, int pointY, bool isBackLog, bool force, TextDrawingMode mode)
+		{
+            foreach (ConsoleButtonString button in buttons)
+                button.DrawTo(graph, pointY, isBackLog, mode);
+		}
+		
+		public override string ToString()
+		{
+			if (buttons == null)
+				return "";
+			StringBuilder builder = new StringBuilder();
+			foreach (ConsoleButtonString button in buttons)
+				builder.Append(button);
+			return builder.ToString();
+		}
+	}
+}

+ 163 - 0
NTERA/Game/Display/ConsoleImagePart.cs

@@ -0,0 +1,163 @@
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Text;
+using System.Windows.Forms;
+using MinorShift.Emuera;
+using MinorShift.Emuera.Content;
+
+namespace NTERA.Game.Display
+{
+	class ConsoleImagePart : AConsoleDisplayPart
+	{
+		public ConsoleImagePart(string resName, string resNameb, int raw_height, int raw_width, int raw_ypos)
+		{
+			top = 0;
+			bottom = Config.FontSize;
+			Str = "";
+			ResourceName = resName ?? "";
+			ButtonResourceName = resNameb;
+			StringBuilder sb = new StringBuilder();
+			sb.Append("<img src='");
+			sb.Append(ResourceName);
+			if(ButtonResourceName != null)
+			{
+				sb.Append("' srcb='");
+				sb.Append(ButtonResourceName);
+			}
+			if(raw_height != 0)
+			{
+				sb.Append("' height='");
+				sb.Append(raw_height.ToString());
+			}
+			if(raw_width != 0)
+			{
+				sb.Append("' width='");
+				sb.Append(raw_height.ToString());
+			}
+			if(raw_ypos != 0)
+			{
+				sb.Append("' ypos='");
+				sb.Append(raw_height.ToString());
+			}
+			sb.Append("'>");
+			AltText = sb.ToString();
+			
+			cImage = AppContents.GetContent<CroppedImage>(ResourceName);
+			if (cImage != null && !cImage.Enabled)
+				cImage = null;
+			if (cImage == null)
+			{
+				Str = AltText;
+				return;
+			}
+			int height = 0;
+			if (cImage.NoResize)
+			{
+				height = cImage.Rectangle.Height;
+				Width = cImage.Rectangle.Width;
+			}
+			else
+			{
+				
+				if (raw_height == 0)
+					height = Config.FontSize;
+				else
+					height = Config.FontSize * raw_height / 100;
+				if (raw_width == 0)
+				{
+					Width = cImage.Rectangle.Width * height / cImage.Rectangle.Height;
+					XsubPixel = ((float)cImage.Rectangle.Width * height) / cImage.Rectangle.Height - Width;
+				}
+				else
+				{
+					Width = Config.FontSize * raw_width / 100;
+					XsubPixel = ((float)Config.FontSize * raw_width / 100f) - Width;
+				}
+			}
+			top = raw_ypos * Config.FontSize / 100;
+			destRect = new Rectangle(0, top, Width, height);
+			if (destRect.Width < 0)
+			{
+				destRect.X = -destRect.Width;
+				Width = -destRect.Width;
+			}
+			if (destRect.Height < 0)
+			{
+				destRect.Y = destRect.Y - destRect.Height;
+				height = -destRect.Height;
+			}
+			bottom = top + height;
+			//if(top > 0)
+			//	top = 0;
+			//if(bottom < Config.FontSize)
+			//	bottom = Config.FontSize;
+			if (ButtonResourceName != null)
+			{
+				cImageB = AppContents.GetContent<CroppedImage>(ButtonResourceName);
+				if (cImageB != null && !cImageB.Enabled)
+					cImageB = null;
+			}
+		}
+
+		private readonly CroppedImage cImage;
+		private readonly CroppedImage cImageB;
+		private readonly int top;
+		private readonly int bottom;
+		private readonly Rectangle destRect;
+		private readonly ImageAttributes ia;
+		public readonly string ResourceName;
+		public readonly string ButtonResourceName;
+		public override int Top => top;
+		public override int Bottom => bottom;
+
+		public override bool CanDivide => false;
+
+		public override void SetWidth(StringMeasure sm, float subPixel)
+		{
+			if (Error)
+			{
+				Width = 0;
+				return;
+			}
+			if (cImage != null)
+				return;
+			Width = sm.GetDisplayLength(Str, Config.Font);
+			XsubPixel = subPixel;
+		}
+
+		public override string ToString()
+		{
+			if (AltText == null)
+				return "";
+			return AltText;
+		}
+
+		public override void DrawTo(Graphics graph, int pointY, bool isSelecting, bool isBackLog, TextDrawingMode mode)
+		{
+			if (Error)
+				return;
+			CroppedImage img = cImage;
+			if (isSelecting && cImageB != null)
+				img = cImageB;
+			Rectangle rect = destRect;
+			//PointX微調整
+			rect.X = destRect.X + PointX + Config.DrawingParam_ShapePositionShift;
+			rect.Y = destRect.Y + pointY;
+
+			if (img != null)
+			{
+				if(ia == null)
+					graph.DrawImage(img.BaseImage.Bitmap, rect, img.Rectangle, GraphicsUnit.Pixel);
+				else
+					graph.DrawImage(img.BaseImage.Bitmap, rect, img.Rectangle.X,img.Rectangle.Y,img.Rectangle.Width,img.Rectangle.Height , GraphicsUnit.Pixel,ia);
+			}
+			else
+			{
+				if (mode == TextDrawingMode.GRAPHICS)
+					graph.DrawString(Str, Config.Font, new SolidBrush(Config.ForeColor), new Point(PointX, pointY));
+				else
+					TextRenderer.DrawText(graph, Str, Config.Font, new Point(PointX, pointY), Config.ForeColor, TextFormatFlags.NoPrefix);
+			}
+		}
+	}
+}

+ 187 - 0
NTERA/Game/Display/ConsoleShapePart.cs

@@ -0,0 +1,187 @@
+using System;
+using System.Drawing;
+using System.Text;
+using System.Windows.Forms;
+using MinorShift.Emuera;
+
+namespace NTERA.Game.Display
+{
+	abstract class ConsoleShapePart : AConsoleColoredPart
+	{
+		public static ConsoleShapePart CreateShape(string shapeType, int[] param, Color color, Color bcolor, bool colorchanged)
+		{
+			string type = shapeType.ToLower();
+			colorchanged = colorchanged || color != Config.ForeColor;
+			StringBuilder sb = new StringBuilder();
+			sb.Append("<shape type='");
+			sb.Append(type);
+			sb.Append("' param='");
+			for (int i = 0; i < param.Length;i++ )
+			{
+				sb.Append(param[i].ToString());
+				if (i < param.Length - 1)
+					sb.Append(", ");
+			}
+			sb.Append("'");
+			if(colorchanged)
+			{
+				sb.Append(" color='");
+				sb.Append(HtmlManager.GetColorToString(color));
+				sb.Append("'");
+			}
+			if(bcolor != Config.FocusColor)
+			{
+				sb.Append(" bcolor='");
+				sb.Append(HtmlManager.GetColorToString(bcolor));
+				sb.Append("'");
+			}
+			sb.Append(">");
+			ConsoleShapePart ret = null;
+			int lineHeight = Config.FontSize;
+			float[] paramPixel = new float[param.Length];
+			for (int i = 0; i < param.Length; i++)
+			{
+				paramPixel[i] = ((float)param[i] * lineHeight) / 100f;
+			}
+			RectangleF rectF;
+
+			switch (type)
+			{
+				case "space":
+					if (paramPixel.Length == 1 && paramPixel[0] >= 0)
+					{
+						rectF = new RectangleF(0, 0, paramPixel[0], lineHeight);
+						ret = new ConsoleSpacePart(rectF);
+					}
+					break;
+				case "rect":
+					if (paramPixel.Length == 1 && paramPixel[0] > 0)
+					{
+						rectF = new RectangleF(0, 0, paramPixel[0], lineHeight);
+						ret = new ConsoleRectangleShapePart(rectF);
+					}
+					else if (paramPixel.Length == 4)
+					{
+						rectF = new RectangleF(paramPixel[0], paramPixel[1], paramPixel[2], paramPixel[3]);
+						//1820a12 サイズ上限撤廃
+						if (rectF.X >= 0 && rectF.Width > 0 && rectF.Height > 0)
+						//	rectF.Y >= 0 && (rectF.Y + rectF.Height) <= lineHeight)
+						{
+							ret = new ConsoleRectangleShapePart(rectF);
+						}
+					}
+					break;
+				case "polygon":
+					break;
+			}
+			if (ret == null)
+			{
+				ret = new ConsoleErrorShapePart(sb.ToString());
+			}
+			ret.AltText = sb.ToString();
+			ret.Color = color;
+			ret.ButtonColor = bcolor;
+			ret.colorChanged = colorchanged;
+			return ret;
+		}
+
+		public override bool CanDivide => false;
+
+		public override string ToString()
+		{
+			if (AltText == null)
+				return "";
+			return AltText;
+		}
+	}
+	
+	internal sealed class ConsoleRectangleShapePart : ConsoleShapePart
+	{
+		public ConsoleRectangleShapePart(RectangleF theRect)
+		{
+			Str = "";
+			originalRectF = theRect;
+			WidthF = theRect.X + theRect.Width;
+			rect.Y = (int)theRect.Y;
+			//if (rect.Y == 0 && theRect.Y >= 0.001f)
+			//	rect.Y = 1;
+			rect.Height = (int)theRect.Height;
+			if (rect.Height == 0 && theRect.Height >= 0.001f)
+				rect.Height = 1;
+			top = Math.Min(0, rect.Y);
+			bottom = Math.Max(Config.FontSize, rect.Y + rect.Height);
+		}
+		private readonly int top;
+		private readonly int bottom;
+		public override int Top => top;
+		public override int Bottom => bottom;
+		readonly RectangleF originalRectF;
+		bool visible;
+		Rectangle rect;
+		public override void DrawTo(Graphics graph, int pointY, bool isSelecting, bool isBackLog, TextDrawingMode mode)
+		{
+			if (!visible)
+				return;
+			Rectangle targetRect = rect;
+			targetRect.X = targetRect.X + PointX;
+			targetRect.Y = targetRect.Y + pointY;
+			Color dcolor = isSelecting ? ButtonColor : Color;
+			graph.FillRectangle(new SolidBrush(dcolor), targetRect);
+		}
+		public override void SetWidth(StringMeasure sm, float subPixel)
+		{
+			float widF = (subPixel + WidthF);
+			Width = (int)(widF);
+			XsubPixel = widF - Width;
+			rect.X = (int)(subPixel + originalRectF.X);
+			rect.Width = Width - rect.X;
+			rect.X += Config.DrawingParam_ShapePositionShift;
+			visible = (rect.X >= 0 && rect.Width > 0);// && rect.Y >= 0 && (rect.Y + rect.Height) <= Config.FontSize);
+		}
+	}
+
+	internal sealed class ConsoleSpacePart : ConsoleShapePart
+	{
+		public ConsoleSpacePart(RectangleF theRect)
+		{
+			Str = "";
+			WidthF = theRect.Width;
+			//Width = width;
+		}
+
+		public override void DrawTo(Graphics graph, int pointY, bool isSelecting, bool isBackLog, TextDrawingMode mode) { }
+		public override void SetWidth(StringMeasure sm,float subPixel)
+		{
+			float widF = (subPixel + WidthF);
+			Width = (int)(widF);
+			XsubPixel = widF - Width;
+		}
+	}
+
+	internal sealed class ConsoleErrorShapePart : ConsoleShapePart
+	{
+		public ConsoleErrorShapePart(string errMes)
+		{
+			Str = errMes;
+			AltText = errMes;
+		}
+
+		public override void DrawTo(Graphics graph, int pointY, bool isSelecting, bool isBackLog, TextDrawingMode mode)
+		{
+			if (mode == TextDrawingMode.GRAPHICS)
+				graph.DrawString(Str, Config.Font, new SolidBrush(Config.ForeColor), new Point(PointX, pointY));
+			else
+				TextRenderer.DrawText(graph, Str, Config.Font, new Point(PointX, pointY), Config.ForeColor, TextFormatFlags.NoPrefix);
+		}
+		public override void SetWidth(StringMeasure sm, float subPixel)
+		{
+			if (Error)
+			{
+				Width = 0;
+				return;
+			}
+			Width = sm.GetDisplayLength(Str, Config.Font);
+			XsubPixel = subPixel;
+		}
+	}
+}

+ 97 - 0
NTERA/Game/Display/ConsoleStyledString.cs

@@ -0,0 +1,97 @@
+using System.Drawing;
+using System.Windows.Forms;
+using MinorShift.Emuera;
+using NTERA.Interop;
+
+namespace NTERA.Game.Display
+{
+	/// <summary>
+	/// 装飾付文字列。stringとStringStyleからなる。
+	/// </summary>
+	internal sealed class ConsoleStyledString : AConsoleColoredPart
+	{
+		private ConsoleStyledString() { }
+		public ConsoleStyledString(string str, StringStyle style)
+		{
+            //if ((StaticConfig.TextDrawingMode != TextDrawingMode.GRAPHICS) && (str.IndexOf('\t') >= 0))
+            //    str = str.Replace("\t", "");
+			Str = str;
+			StringStyle = style;
+			Font = Config.GetFont(style.Fontname, style.FontStyle);
+			if (Font == null)
+			{
+				Error = true;
+				return;
+			}
+			Color = style.Color;
+			ButtonColor = style.ButtonColor;
+            colorChanged = style.ColorChanged;
+			if (!colorChanged && Color != Config.ForeColor)
+				colorChanged = true;
+			PointX = -1;
+			Width = -1;
+		}
+		public Font Font{ get; private set;}
+		public StringStyle StringStyle{ get; private set;}
+		public override bool CanDivide => true;
+
+		//単一のボタンフラグ
+		//public bool IsButton { get; set; }
+		//indexの文字数の前方文字列とindex以降の後方文字列に分割
+		public ConsoleStyledString DivideAt(int index, StringMeasure sm)
+		{
+			//if ((index <= 0)||(index > Str.Length)||this.Error)
+			//	return null;
+			ConsoleStyledString ret = DivideAt(index);
+			if (ret == null)
+				return null;
+			SetWidth(sm, XsubPixel);
+			ret.SetWidth(sm, XsubPixel);
+			return ret;
+		}
+		public ConsoleStyledString DivideAt(int index)
+		{
+			if ((index <= 0) || (index > Str.Length) || Error)
+				return null;
+			string str = Str.Substring(index, Str.Length - index);
+			Str = Str.Substring(0, index);
+			ConsoleStyledString ret = new ConsoleStyledString();
+			ret.Font = Font;
+			ret.Str = str;
+			ret.Color = Color;
+			ret.ButtonColor = ButtonColor;
+			ret.colorChanged = colorChanged;
+			ret.StringStyle = StringStyle;
+			ret.XsubPixel = XsubPixel;
+			return ret;
+		}
+
+		public override void SetWidth(StringMeasure sm, float subPixel)
+		{
+			if (Error)
+			{
+				Width = 0;
+				return;
+			}
+			Width = sm.GetDisplayLength(Str, Font);
+			XsubPixel = subPixel;
+		}
+
+		public override void DrawTo(Graphics graph, int pointY, bool isSelecting, bool isBackLog, TextDrawingMode mode)
+		{
+			if (Error)
+				return;
+			Color color = Color;
+			if(isSelecting)
+				color = ButtonColor;
+			else if (isBackLog && !colorChanged)
+                color = Config.LogColor;
+				
+			if (mode == TextDrawingMode.GRAPHICS)
+				graph.DrawString(Str, Font, new SolidBrush(color), new Point(PointX, pointY));
+			else
+				TextRenderer.DrawText(graph, Str, Font, new Point(PointX, pointY), color, TextFormatFlags.NoPrefix);
+
+		}
+	}
+}

+ 1050 - 0
NTERA/Game/Display/HTMLManager.cs

@@ -0,0 +1,1050 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Text;
+using System.Text.RegularExpressions;
+using MinorShift.Emuera;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.Sub;
+using NTERA.Interop;
+
+namespace NTERA.Game.Display
+{
+	//TODO:1810~
+	/* Emuera用Htmlもどきが実装すべき要素
+	 * (できるだけhtmlとConsoleDisplayLineとの1:1対応を目指す。<b>と<strong>とか同じ結果になるタグを重複して実装しない)
+	 * <p align=""></p> ALIGNMENT命令相当・行頭から行末のみ・行末省略可
+	 * <nobr></nobr> PRINTSINGLE相当・行頭から行末のみ・行末省略可
+	 * <b><i><u><s> フォント各種・オーバーラップ問題は保留
+	 * <button value=""></button> ボタン化・htmlでは明示しない限りボタン化しない
+	 * <font face="" color="" bcolor=""></font> フォント指定 色指定 ボタン選択中色指定
+	 * 追加<!-- --> コメント
+	 * <nonbutton title='~~'> 
+	 * <img src='~~' srcb='~~'> 
+	 * <shape type='rect' param='0,0,0,0'> 
+	 * エスケープ
+	 * &amp; &gt; &lt; &quot; &apos; &<>"' ERBにおける利便性を考えると属性値の指定には"よりも'を使いたい。HTML4.1にはないがaposを入れておく
+	 * &#nn; &#xnn; Unicode参照 #xFFFF以上は却下
+	 */
+	/* このクラスがサポートすべきもの
+	 * html から ConsoleDisplayLine[] //主に表示用
+	 * ConsoleDisplayLine[] から html //現在の表示をstr化して保存?
+	 * html から ConsoleDisplayLine[] を経て html //表示を行わずに改行が入る位置のチェックができるかも
+	 * html から PlainText(非エスケープ)//
+	 * Text から エスケープ済Text
+	 */
+	/// <summary>
+	/// EmueraConsoleのなんちゃってHtml解決用クラス
+	/// </summary>
+	internal static class HtmlManager
+	{
+		static HtmlManager()
+		{
+			repDic.Add('&', "&amp;");
+			repDic.Add('>', "&gt;");
+			repDic.Add('<', "&lt;");
+			repDic.Add('\"', "&quot;");
+			repDic.Add('\'', "&apos;");
+		}
+		static readonly char[] rep = { '&', '>', '<', '\"', '\'' };
+		static readonly Dictionary<char, string> repDic = new Dictionary<char, string>();
+		private sealed class HtmlAnalzeStateFontTag
+		{
+			public int Color = -1;
+			public int BColor = -1;
+			public string FontName;
+			//public int PointX = 0;
+			//public bool PointXisLocked = false;
+		}
+
+		private sealed class HtmlAnalzeStateButtonTag
+		{
+			public bool IsButton = true;
+			public bool IsButtonTag = true;
+			public int ButtonValueInt;
+			public string ButtonValueStr;
+			public string ButtonTitle;
+			public bool ButtonIsInteger;
+			public int PointX;
+			public bool PointXisLocked;
+		}
+
+		private sealed class HtmlAnalzeState
+		{
+			public bool LineHead = true;//行頭フラグ。一度もテキストが出てきてない状態
+			public FontStyle FontStyle = FontStyle.Regular;
+			public List<HtmlAnalzeStateFontTag> FonttagList = new List<HtmlAnalzeStateFontTag>();
+			public bool FlagNobr;//falseの時に</nobr>するとエラー
+			public bool FlagP;//falseの時に</p>するとエラー
+			public bool FlagNobrClosed;//trueの時に</nobr>するとエラー
+			public bool FlagPClosed;//trueの時に</p>するとエラー
+			public DisplayLineAlignment Alignment = DisplayLineAlignment.LEFT;
+
+			/// <summary>
+			/// 今まで追加された文字列についてのボタンタグ情報
+			/// </summary>
+			public HtmlAnalzeStateButtonTag LastButtonTag;
+			/// <summary>
+			/// 最新のボタンタグ情報
+			/// </summary>
+			public HtmlAnalzeStateButtonTag CurrentButtonTag;
+
+			public bool FlagBr;//<br>による強制改行の予約
+			public bool FlagButton;//<button></button>によるボタン化の予約
+
+			public StringStyle GetSS()
+			{
+				Color c = Config.ForeColor;
+				Color b = Config.FocusColor;
+				string fontname = null;
+				bool colorChanged = false;
+				if (FonttagList.Count > 0)
+				{
+					HtmlAnalzeStateFontTag font = FonttagList[FonttagList.Count - 1];
+					fontname = font.FontName;
+					if (font.Color >= 0)
+					{
+						colorChanged = true;
+						c = Color.FromArgb(font.Color >> 16, (font.Color >> 8) & 0xFF, font.Color & 0xFF);
+					}
+					if (font.BColor >= 0)
+					{
+						b = Color.FromArgb(font.BColor >> 16, (font.BColor >> 8) & 0xFF, font.BColor & 0xFF);
+					}
+				}
+				return new StringStyle(c, colorChanged, b, FontStyle, fontname);
+			}
+		}
+
+		/// <summary>
+		/// 表示行からhtmlへの変換
+		/// </summary>
+		/// <param name="lines"></param>
+		/// <returns></returns>
+		public static string DisplayLine2Html(ConsoleDisplayLine[] lines, bool needPandN)
+		{
+			if (lines == null || lines.Length == 0)
+				return "";
+			StringBuilder b = new StringBuilder();
+			if (needPandN)
+			{
+				switch (lines[0].Align)
+				{
+					case DisplayLineAlignment.LEFT:
+						b.Append("<p align='left'>");
+						break;
+					case DisplayLineAlignment.CENTER:
+						b.Append("<p align='center'>");
+						break;
+					case DisplayLineAlignment.RIGHT:
+						b.Append("<p align='right'>");
+						break;
+				}
+				b.Append("<nobr>");
+			}
+			for (int dispCounter = 0; dispCounter < lines.Length; dispCounter++)
+			{
+				if (dispCounter != 0)
+					b.Append("<br>");
+				ConsoleButtonString[] buttons = lines[dispCounter].Buttons;
+				for (int buttonCounter = 0; buttonCounter < buttons.Length; buttonCounter++)
+				{
+					string titleValue = null;
+					if (!string.IsNullOrEmpty(buttons[buttonCounter].Title))
+						titleValue = Escape(buttons[buttonCounter].Title);
+					bool hasTag = buttons[buttonCounter].IsButton || titleValue != null
+						|| buttons[buttonCounter].PointXisLocked;
+					if (hasTag)
+					{
+						if (buttons[buttonCounter].IsButton)
+						{
+							string attrValue = Escape(buttons[buttonCounter].Inputs);
+							b.Append("<button value='");
+							b.Append(attrValue);
+							b.Append("'");
+						}
+						else
+						{
+							b.Append("<nonbutton");
+						}
+						if (titleValue != null)
+						{
+							b.Append(" title='");
+							b.Append(titleValue);
+							b.Append("'");
+						}
+						if (buttons[buttonCounter].PointXisLocked)
+						{
+							b.Append(" pos='");
+							b.Append(buttons[buttonCounter].RelativePointX.ToString());
+							b.Append("'");
+						}
+						b.Append(">");
+					}
+					AConsoleDisplayPart[] parts = buttons[buttonCounter].StrArray;
+					for (int cssCounter = 0; cssCounter < parts.Length; cssCounter++)
+					{
+						if (parts[cssCounter] is ConsoleStyledString)
+						{
+							ConsoleStyledString css = parts[cssCounter] as ConsoleStyledString;
+							b.Append(getStringStyleStartingTag(css.StringStyle));
+							b.Append(Escape(css.Str));
+							b.Append(getClosingStyleStartingTag(css.StringStyle));
+						}
+						else if (parts[cssCounter] is ConsoleImagePart)
+						{
+							b.Append(parts[cssCounter].AltText);
+							//ConsoleImagePart img = (ConsoleImagePart)parts[cssCounter];
+							//b.Append("<img src='");
+							//b.Append(Escape(img.ResourceName));
+							//if(img.ButtonResourceName != null)
+							//{
+							//	b.Append("' srcb='");
+							//	b.Append(Escape(img.ButtonResourceName));
+							//}
+							//b.Append("'>");
+						}
+						else if (parts[cssCounter] is ConsoleShapePart)
+						{
+							b.Append(parts[cssCounter].AltText);
+						}
+
+					}
+					if (hasTag)
+					{
+						if (buttons[buttonCounter].IsButton)
+							b.Append("</button>");
+						else
+							b.Append("</nonbutton>");
+					}
+
+				}
+			}
+			if(needPandN)
+			{
+				b.Append("</nobr>");
+				b.Append("</p>");
+			}
+			return b.ToString();
+		}
+
+		public static string[] HtmlTagSplit(string str)
+		{
+			List<string> strList = new List<string>();
+			StringStream st = new StringStream(str);
+			int found = -1;
+			while (!st.EOS)
+			{
+				found = st.Find('<');
+				if (found < 0)
+				{
+					strList.Add(st.Substring());
+					break;
+				}
+
+				if (found > 0)
+				{
+					strList.Add(st.Substring(st.CurrentPosition, found));
+					st.CurrentPosition += found;
+				}
+				found = st.Find('>');
+				if(found < 0)
+					return null;
+				found++;
+				strList.Add(st.Substring(st.CurrentPosition, found));
+				st.CurrentPosition += found;
+			}
+			string[] ret = new string[strList.Count];
+			strList.CopyTo(ret);
+			return ret;
+		}
+		
+		/// <summary>
+		/// htmlから表示行の作成
+		/// </summary>
+		/// <param name="str">htmlテキスト</param>
+		/// <param name="sm"></param>
+		/// <param name="console">実際の表示に使わないならnullにする</param>
+        /// <param name="noLineBreak">Disable any line breaks in resulting ConsoleDisplayLine</param>
+		/// <returns></returns>
+		public static ConsoleDisplayLine[] Html2DisplayLine(string str, StringMeasure sm, IConsole console)
+        {
+            bool noBr = false;
+            DisplayLineAlignment alignment;
+            List<ConsoleButtonString> buttonList = Html2ButtonList(str, console, out noBr, out alignment);
+            ConsoleDisplayLine[] ret = PrintStringBuffer.ButtonsToDisplayLines(buttonList, sm, noBr, false);
+
+            foreach (ConsoleDisplayLine dl in ret)
+            {
+                dl.SetAlignment(alignment);
+            }
+            return ret;
+        }
+
+        public static List<ConsoleButtonString> Html2ButtonList(string str, IConsole console, out bool noBr, out DisplayLineAlignment alignment)
+        {
+            HtmlAnalzeState state;
+            List<ConsoleButtonString> buttonList = new List<ConsoleButtonString>();
+            List<AConsoleDisplayPart> cssList = new List<AConsoleDisplayPart>();
+            buttonList = new List<ConsoleButtonString>();
+            StringStream st = new StringStream(str);
+            int found;
+            bool hasComment = str.IndexOf("<!--") >= 0;
+            bool hasReturn = str.IndexOf('\n') >= 0;
+            state = new HtmlAnalzeState();
+            while (!st.EOS)
+            {
+                found = st.Find('<');
+                if (hasReturn)
+                {
+                    int rFound = st.Find('\n');
+                    if (rFound >= 0 && (found > rFound || found < 0))
+                        found = rFound;
+                }
+                if (found < 0)
+                {
+                    string txt = Unescape(st.Substring());
+                    cssList.Add(new ConsoleStyledString(txt, state.GetSS()));
+                    if (state.FlagPClosed)
+                        throw new CodeEE("</p>の後にテキストがあります");
+                    if (state.FlagNobrClosed)
+                        throw new CodeEE("</nobr>の後にテキストがあります");
+                    break;
+                }
+
+	            if (found > 0)
+	            {
+		            string txt = Unescape(st.Substring(st.CurrentPosition, found));
+		            cssList.Add(new ConsoleStyledString(txt, state.GetSS()));
+		            state.LineHead = false;
+		            st.CurrentPosition += found;
+	            }
+	            //コメントタグのみ特別扱い
+                if (hasComment && st.CurrentEqualTo("<!--"))
+                {
+                    st.CurrentPosition += 4;
+                    found = st.Find("-->");
+                    if (found < 0)
+                        throw new CodeEE("コメンdト終了タグ\"-->\"がみつかりません");
+                    st.CurrentPosition += found + 3;
+                    continue;
+                }
+                if (hasReturn && st.Current == '\n')//テキスト中の\nは<br>として扱う
+                {
+                    state.FlagBr = true;
+                    st.ShiftNext();
+                }
+                else//タグ解析
+                {
+                    st.ShiftNext();
+                    AConsoleDisplayPart part = tagAnalyze(state, st);
+                    if (st.Current != '>')
+                        throw new CodeEE("タグ終端'>'が見つかりません");
+                    if (part != null)
+                            cssList.Add(part);
+                    st.ShiftNext();
+                }
+
+                if (state.FlagBr)
+                {
+                    state.LastButtonTag = state.CurrentButtonTag;
+                    if (cssList.Count > 0)
+                        buttonList.Add(cssToButton(cssList, state, console));
+                    buttonList.Add(null);
+                }
+                if (state.FlagButton && cssList.Count > 0)
+                {
+                    buttonList.Add(cssToButton(cssList, state, console));
+                }
+                state.FlagBr = false;
+                state.FlagButton = false;
+                state.LastButtonTag = state.CurrentButtonTag;
+            }
+            //</nobr></p>は省略許可
+            if (state.CurrentButtonTag != null || state.FontStyle != FontStyle.Regular || state.FonttagList.Count > 0)
+                throw new CodeEE("閉じられていないタグがあります");
+            if (cssList.Count > 0)
+                buttonList.Add(cssToButton(cssList, state, console));
+
+            foreach (ConsoleButtonString button in buttonList)
+            {
+                if (button != null && button.PointXisLocked)
+                {
+                    if (!state.FlagNobr)
+                        throw new CodeEE("<nobr>が設定されていない行ではpos属性は使用できません");
+                    if (state.Alignment != DisplayLineAlignment.LEFT)
+                        throw new CodeEE("alignがleftでない行ではpos属性は使用できません");
+                    break;
+                }
+            }
+            alignment = state.Alignment;
+            noBr = state.FlagNobr;
+            return buttonList;
+        }
+
+        public static string Html2PlainText(string str)
+		{
+			string ret = Regex.Replace(str, "\\<[^<]*\\>", "");
+			return Unescape(ret);
+		}
+
+		public static string Escape(string str)
+		{
+			//Net4.5では便利なクラスがあるらしい
+			//return System.Web.HttpUtility.HtmlEncode(str);
+
+			int index = 0;
+			int found = 0;
+			StringBuilder b = new StringBuilder();
+			while (index < str.Length)
+			{
+				found = str.IndexOfAny(rep, index);
+				if (found < 0)//見つからなければ以降を追加して終了
+				{
+					b.Append(str.Substring(index));
+					break;
+				}
+				if (found > index)//間に非エスケープ文字があるなら追加しておく
+					b.Append(str.Substring(index, found - index));
+				string repnew = repDic[str[found]];
+				b.Append(repnew);
+				index = found + 1;
+			}
+			return b.ToString();
+		}
+
+		public static string Unescape(string str)
+		{
+			int index = 0;
+			int found = str.IndexOf('&', index);
+			if (found < 0)
+				return str;
+			StringBuilder b = new StringBuilder();
+			// &~; をひたすら置換するだけ
+			while (index < str.Length)
+			{
+				found = str.IndexOf('&', index);
+				if (found < 0)//見つからなければ以降を追加して終了
+				{
+					b.Append(str.Substring(index));
+					break;
+				}
+				if (found > index)//間に非エスケープ文字があるなら追加しておく
+					b.Append(str.Substring(index, found - index));
+				index = found;
+				found = str.IndexOf(';', index);
+				if (found <= index + 1)
+				{
+					if (found < 0)
+						throw new CodeEE("'&'に対応する';'がみつかりません");
+					throw new CodeEE("'&'と';'が連続しています");
+				}
+				string escWordRow = str.Substring(index + 1, found - index - 1);
+				index = found + 1;
+				string escWord = escWordRow.ToLower();
+				int unicode = 0;
+				switch (escWord)
+				{
+					case "nbsp": b.Append(" "); break;
+					case "amp": b.Append("&"); break;
+					case "gt": b.Append(">"); break;
+					case "lt": b.Append("<"); break;
+					case "quot": b.Append("\""); break;
+					case "apos": b.Append("\'"); break;
+					default:
+						{
+							int iBbase = 10;
+							if (escWord[0] != '#')
+								throw new CodeEE("\"&" + escWordRow + ";\"は適切な文字参照ではありません");
+							if (escWord.Length > 1 && escWord[1] == 'x')
+							{
+								iBbase = 16;
+								escWord = escWord.Substring(2);
+							}
+							else
+								escWord = escWord.Substring(1);
+							try
+							{
+								unicode = Convert.ToInt32(escWord, iBbase);
+							}
+							catch
+							{
+
+								throw new CodeEE("\"&" + escWordRow + ";\"は適切な文字参照ではありません");
+							}
+
+							if (unicode < 0 || unicode > 0xFFFF)
+								throw new CodeEE("\"&" + escWordRow + ";\"はUnicodeの範囲外です(サロゲートペアは使えません)");
+							b.Append((char)unicode);
+							break;
+						}
+				}
+			}
+			return b.ToString();
+		}
+
+		/// <summary>
+		/// ここまでのcssをボタン化。発生原因はbrタグ、行末、ボタンタグ
+		/// </summary>
+		/// <param name="cssList"></param>
+		/// <param name="isbutton"></param>
+		/// <param name="state"></param>
+		/// <param name="console"></param>
+		/// <returns></returns>
+		private static ConsoleButtonString cssToButton(List<AConsoleDisplayPart> cssList, HtmlAnalzeState state, IConsole console)
+		{
+			AConsoleDisplayPart[] css = new AConsoleDisplayPart[cssList.Count];
+			cssList.CopyTo(css);
+			cssList.Clear();
+			ConsoleButtonString ret = null;
+			if (state.LastButtonTag != null && state.LastButtonTag.IsButton)
+			{
+				if (state.LastButtonTag.ButtonIsInteger)
+					ret = new ConsoleButtonString(console, css, state.LastButtonTag.ButtonValueInt, state.LastButtonTag.ButtonValueStr);
+				else
+					ret = new ConsoleButtonString(console, css, state.LastButtonTag.ButtonValueStr);
+			}
+			else
+			{
+				ret = new ConsoleButtonString(console, css);
+				ret.Title = null;
+			}
+			if (state.LastButtonTag != null)
+			{
+				ret.Title = state.LastButtonTag.ButtonTitle;
+				if(state.LastButtonTag.PointXisLocked)
+				{
+					ret.LockPointX(state.LastButtonTag.PointX);
+				}
+			}
+			return ret;
+		}
+
+		public static string GetColorToString(Color color)
+		{
+			StringBuilder b = new StringBuilder();
+			b.Append("#");
+			int colorValue = color.R * 0x10000 + color.G * 0x100 + color.B;
+			b.Append(colorValue.ToString("X6"));
+			return b.ToString();
+		}
+		private static string getStringStyleStartingTag(StringStyle style)
+		{
+			bool fontChanged = !((style.Fontname == null || style.Fontname == Config.FontName)&& !style.ColorChanged && (style.ButtonColor == Config.FocusColor));
+			if (!fontChanged && style.FontStyle == FontStyle.Regular)
+				return "";
+			StringBuilder b = new StringBuilder();
+			if (fontChanged)
+			{
+				b.Append("<font");
+				if (style.Fontname != null && style.Fontname != Config.FontName)
+				{
+					b.Append(" face='");
+					b.Append(Escape(style.Fontname));
+					b.Append("'");
+				}
+				if (style.ColorChanged)
+				{
+					b.Append(" color='#");
+					int colorValue = style.Color.R * 0x10000 + style.Color.G * 0x100 + style.Color.B;
+					b.Append(colorValue.ToString("X6"));
+					b.Append("'");
+				}
+				if (style.ButtonColor != Config.FocusColor)
+				{
+					b.Append(" bcolor='#");
+					int colorValue = style.ButtonColor.R * 0x10000 + style.ButtonColor.G * 0x100 + style.ButtonColor.B;
+					b.Append(colorValue.ToString("X6"));
+					b.Append("'");
+				}
+				b.Append(">");
+			}
+			if (style.FontStyle != FontStyle.Regular)
+			{
+				if ((style.FontStyle & FontStyle.Strikeout) != FontStyle.Regular)
+					b.Append("<s>");
+				if ((style.FontStyle & FontStyle.Underline) != FontStyle.Regular)
+					b.Append("<u>");
+				if ((style.FontStyle & FontStyle.Italic) != FontStyle.Regular)
+					b.Append("<i>");
+				if ((style.FontStyle & FontStyle.Bold) != FontStyle.Regular)
+					b.Append("<b>");
+			}
+
+			return b.ToString();
+		}
+
+		private static string getClosingStyleStartingTag(StringStyle style)
+		{
+			bool fontChanged = !((style.Fontname == null || style.Fontname == Config.FontName) && !style.ColorChanged && (style.ButtonColor == Config.FocusColor));
+			if (!fontChanged && style.FontStyle == FontStyle.Regular)
+				return "";
+			StringBuilder b = new StringBuilder();
+			if (style.FontStyle != FontStyle.Regular)
+			{
+				if ((style.FontStyle & FontStyle.Bold) != FontStyle.Regular)
+					b.Append("</b>");
+				if ((style.FontStyle & FontStyle.Italic) != FontStyle.Regular)
+					b.Append("</i>");
+				if ((style.FontStyle & FontStyle.Underline) != FontStyle.Regular)
+					b.Append("</u>");
+				if ((style.FontStyle & FontStyle.Strikeout) != FontStyle.Regular)
+					b.Append("</s>");
+			}
+			if (fontChanged)
+				b.Append("</font>");
+			return b.ToString();
+		}
+
+		private static AConsoleDisplayPart tagAnalyze(HtmlAnalzeState state, StringStream st)
+		{
+			bool endTag = (st.Current == '/');
+			string tag;
+			if (endTag)
+			{
+				st.ShiftNext();
+				int found = st.Find('>');
+				if (found < 0)
+				{
+					st.CurrentPosition = st.RowString.Length;
+					return null;//戻り先でエラーを出す
+				}
+				tag = st.Substring(st.CurrentPosition, found).Trim();
+				st.CurrentPosition += found;
+				FontStyle endStyle = FontStyle.Strikeout;
+				switch (tag.ToLower())
+				{
+					case "b": endStyle = FontStyle.Bold; goto case "s";
+					case "i": endStyle = FontStyle.Italic; goto case "s";
+					case "u": endStyle = FontStyle.Underline; goto case "s";
+					case "s":
+						if ((state.FontStyle & endStyle) == FontStyle.Regular)
+							throw new CodeEE("</" + tag + ">の前に<" + tag + ">がありません");
+						state.FontStyle ^= endStyle;
+						return null;
+					case "p":
+						if ((!state.FlagP) || (state.FlagPClosed))
+							throw new CodeEE("</p>の前に<p>がありません");
+						state.FlagPClosed = true;
+						return null;
+					case "nobr":
+						if ((!state.FlagNobr) || (state.FlagNobrClosed))
+							throw new CodeEE("</nobr>の前に<nobr>がありません");
+						state.FlagNobrClosed = true;
+						return null;
+					case "font":
+						if (state.FonttagList.Count == 0)
+							throw new CodeEE("</font>の前に<font>がありません");
+						state.FonttagList.RemoveAt(state.FonttagList.Count - 1);
+						return null;
+					case "button":
+						if (state.CurrentButtonTag == null || !state.CurrentButtonTag.IsButtonTag)
+							throw new CodeEE("</button>の前に<button>がありません");
+						state.CurrentButtonTag = null;
+						state.FlagButton = true;
+						return null;
+					case "nonbutton":
+						if (state.CurrentButtonTag == null || state.CurrentButtonTag.IsButtonTag)
+							throw new CodeEE("</nonbutton>の前に<nonbutton>がありません");
+						state.CurrentButtonTag = null;
+						state.FlagButton = true;
+						return null;
+					default:
+						throw new CodeEE("終了タグ</"+tag+">は解釈できません");
+				}
+				//goto error;
+			}
+			//以降は開始タグ
+
+			bool tempUseMacro = LexicalAnalyzer.UseMacro;
+			WordCollection wc = null;
+			try
+			{
+				LexicalAnalyzer.UseMacro = false;//一時的にマクロ展開をやめる
+				tag = LexicalAnalyzer.ReadSingleIdentifier(st);
+				LexicalAnalyzer.SkipWhiteSpace(st);
+				if (st.Current != '>')
+					wc = LexicalAnalyzer.Analyse(st, LexEndWith.GreaterThan, LexAnalyzeFlag.AllowAssignment | LexAnalyzeFlag.AllowSingleQuotationStr);
+			}
+			finally
+			{
+				LexicalAnalyzer.UseMacro = tempUseMacro;
+			}
+			if (string.IsNullOrEmpty(tag))
+				goto error;
+			IdentifierWord word;
+			FontStyle newStyle = FontStyle.Strikeout;
+            switch (tag.ToLower())
+			{
+				case "b": newStyle = FontStyle.Bold; goto case "s";
+				case "i": newStyle = FontStyle.Italic; goto case "s";
+				case "u": newStyle = FontStyle.Underline; goto case "s";
+				case "s":
+					if (wc != null)
+						throw new CodeEE("<" + tag + ">タグにに属性が設定されています");
+					if ((state.FontStyle & newStyle) != FontStyle.Regular)
+						throw new CodeEE("<" + tag + ">が二重に使われています");
+					state.FontStyle |= newStyle;
+						return null;
+				case "br":
+					if (wc != null)
+						throw new CodeEE("<" + tag + ">タグにに属性が設定されています");
+					state.FlagBr = true;
+						return null;
+				case "nobr":
+					if (wc != null)
+						throw new CodeEE("<" + tag + ">タグに属性が設定されています");
+					if (!state.LineHead)
+						throw new CodeEE("<nobr>が行頭以外で使われています");
+					if (state.FlagNobr)
+						throw new CodeEE("<nobr>が2度以上使われています");
+					state.FlagNobr = true;
+						return null;
+				case "p":
+					{
+						if (wc == null)
+							throw new CodeEE("<" + tag + ">タグに属性が設定されていません");
+						if (!state.LineHead)
+							throw new CodeEE("<p>が行頭以外で使われています");
+						if (state.FlagNobr)
+							throw new CodeEE("<p>が2度以上使われています");
+						word = wc.Current as IdentifierWord;
+						wc.ShiftNext();
+						OperatorWord op = wc.Current as OperatorWord;
+						wc.ShiftNext();
+						LiteralStringWord attr = wc.Current as LiteralStringWord;
+						wc.ShiftNext();
+						if (!wc.EOL || word == null || op == null || op.Code != OperatorCode.Assignment || attr == null)
+							goto error;
+						if (!word.Code.Equals("align", StringComparison.OrdinalIgnoreCase))
+							throw new CodeEE("<p>タグの属性名" + word.Code + "は解釈できません");
+						string attrValue = Unescape(attr.Str);
+						switch (attrValue.ToLower())
+						{
+							case "left":
+								state.Alignment = DisplayLineAlignment.LEFT;
+								break;
+							case "center":
+								state.Alignment = DisplayLineAlignment.CENTER;
+								break;
+							case "right":
+								state.Alignment = DisplayLineAlignment.RIGHT;
+								break;
+							default:
+								throw new CodeEE("属性値" + attr.Str + "は解釈できません");
+						}
+						state.FlagP = true;
+						return null;
+					}
+				case "img":
+					{
+						if (wc == null)
+							throw new CodeEE("<" + tag + ">タグに属性が設定されていません");
+						string attrValue = null;
+						string src = null;
+						string srcb = null;
+						int height = 0;
+						int width = 0;
+						int ypos = 0;
+						while (wc != null && !wc.EOL)
+						{
+							word = wc.Current as IdentifierWord;
+							wc.ShiftNext();
+							OperatorWord op = wc.Current as OperatorWord;
+							wc.ShiftNext();
+							LiteralStringWord attr = wc.Current as LiteralStringWord;
+							wc.ShiftNext();
+							if (word == null || op == null || op.Code != OperatorCode.Assignment || attr == null)
+								goto error;
+							attrValue = Unescape(attr.Str);
+							if (word.Code.Equals("src", StringComparison.OrdinalIgnoreCase))
+							{
+								if (src != null)
+									throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
+								src = attrValue;
+							}
+							else if (word.Code.Equals("srcb", StringComparison.OrdinalIgnoreCase))
+							{
+								if (srcb != null)
+									throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
+								srcb = attrValue;
+							}
+							else if (word.Code.Equals("height", StringComparison.OrdinalIgnoreCase))
+							{
+								if (height != 0)
+									throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
+								if (!int.TryParse(attrValue, out height))
+									throw new CodeEE("<" + tag + ">タグのheight属性の属性値が数値として解釈できません");
+							}
+							else if (word.Code.Equals("width", StringComparison.OrdinalIgnoreCase))
+							{
+								if (width != 0)
+									throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
+								if (!int.TryParse(attrValue, out width))
+									throw new CodeEE("<" + tag + ">タグのwidth属性の属性値が数値として解釈できません");
+							}
+							else if (word.Code.Equals("ypos", StringComparison.OrdinalIgnoreCase))
+							{
+								if (ypos != 0)
+									throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
+								if (!int.TryParse(attrValue, out ypos))
+									throw new CodeEE("<" + tag + ">タグのypos属性の属性値が数値として解釈できません");
+							}
+							else
+								throw new CodeEE("<" + tag + ">タグの属性名" + word.Code + "は解釈できません");
+						}
+						if (src == null)
+							throw new CodeEE("<" + tag + ">タグにsrc属性が設定されていません");
+						return new ConsoleImagePart(src, srcb, height, width, ypos);
+					}
+
+				case "shape":
+					{
+						if (wc == null)
+							throw new CodeEE("<" + tag + ">タグに属性が設定されていません");
+						int[] param = null;
+						string type = null;
+						int color = -1;
+						int bcolor = -1;
+						while (!wc.EOL)
+						{
+							word = wc.Current as IdentifierWord;
+							wc.ShiftNext();
+							OperatorWord op = wc.Current as OperatorWord;
+							wc.ShiftNext();
+							LiteralStringWord attr = wc.Current as LiteralStringWord;
+							wc.ShiftNext();
+							if (word == null || op == null || op.Code != OperatorCode.Assignment || attr == null)
+								goto error;
+							string attrValue = Unescape(attr.Str);
+							switch (word.Code.ToLower())
+							{
+								case "color":
+									if (color >= 0)
+										throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
+									color = stringToColorInt32(attrValue);
+									break;
+								case "bcolor":
+									if (bcolor >= 0)
+										throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
+									bcolor = stringToColorInt32(attrValue);
+									break;
+								case "type":
+									if (type != null)
+										throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
+									type = attrValue;
+									break;
+								case "param":
+									if (param != null)
+										throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
+									{
+										string[] tokens = attrValue.Split(',');
+										param = new int[tokens.Length];
+										for (int i = 0; i < tokens.Length; i++)
+										{
+											if (!int.TryParse(tokens[i], out param[i]))
+												throw new CodeEE("<" + tag + ">タグの" + word.Code + "属性の属性値が数値として解釈できません");
+										}
+										break;
+									}
+								default:
+									throw new CodeEE("<" + tag + ">タグの属性名" + word.Code + "は解釈できません");
+							}
+						}
+						if (param == null)
+							throw new CodeEE("<" + tag + ">タグにparam属性が設定されていません");
+						if (type == null)
+							throw new CodeEE("<" + tag + ">タグにtype属性が設定されていません");
+						Color c = Config.ForeColor;
+						Color b = Config.FocusColor;
+						if (color >= 0)
+						{
+							c = Color.FromArgb(color >> 16, (color >> 8) & 0xFF, color & 0xFF);
+						}
+						if (bcolor >= 0)
+						{
+							b = Color.FromArgb(bcolor >> 16, (bcolor >> 8) & 0xFF, bcolor & 0xFF);
+						}
+						return ConsoleShapePart.CreateShape(type, param, c, b, color >= 0);
+					}
+				case "button":
+				case "nonbutton":
+					{
+						if (state.CurrentButtonTag != null)
+							throw new CodeEE("<button>又は<nonbutton>が入れ子にされています");
+						HtmlAnalzeStateButtonTag buttonTag = new HtmlAnalzeStateButtonTag();
+						bool isButton = tag.ToLower() == "button";
+						string attrValue = null;
+						string value = null;
+						//if (wc == null)
+						//	throw new CodeEE("<" + tag + ">タグに属性が設定されていません");
+						while (wc != null && !wc.EOL)
+						{
+							word = wc.Current as IdentifierWord;
+							wc.ShiftNext();
+							OperatorWord op = wc.Current as OperatorWord;
+							wc.ShiftNext();
+							LiteralStringWord attr = wc.Current as LiteralStringWord;
+							wc.ShiftNext();
+							if (word == null || op == null || op.Code != OperatorCode.Assignment || attr == null)
+								goto error;
+							attrValue = Unescape(attr.Str);
+							if (word.Code.Equals("value", StringComparison.OrdinalIgnoreCase))
+							{
+								if (!isButton)
+									throw new CodeEE("<" + tag + ">タグにvalue属性が設定されています");
+								if (value != null)
+										throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
+								value = attrValue;
+							}
+							else if (word.Code.Equals("title", StringComparison.OrdinalIgnoreCase))
+							{
+								if (buttonTag.ButtonTitle != null)
+										throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
+								buttonTag.ButtonTitle = attrValue;
+							}
+							else if (word.Code.Equals("pos", StringComparison.OrdinalIgnoreCase))
+							{
+								//throw new NotImplCodeEE();
+								int pos = 0;
+								if (buttonTag.PointXisLocked)
+										throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
+								if (!int.TryParse(attrValue, out pos))
+									throw new CodeEE("<" + tag + ">タグのpos属性の属性値が数値として解釈できません");
+								buttonTag.PointX = pos;
+								buttonTag.PointXisLocked = true;
+							}
+							else
+								throw new CodeEE("<" + tag + ">タグの属性名" + word.Code + "は解釈できません");
+						}
+						if (isButton)
+						{
+							//if (value == null)
+							//	throw new CodeEE("<" + tag + ">タグにvalue属性が設定されていません");
+							int intValue = 0;
+							buttonTag.ButtonIsInteger = (int.TryParse(value, out intValue));
+							buttonTag.ButtonValueInt = intValue;
+							buttonTag.ButtonValueStr = value;
+						}
+						buttonTag.IsButton = value != null;
+						buttonTag.IsButtonTag = isButton;
+						state.CurrentButtonTag = buttonTag;
+						state.FlagButton = true;
+						return null;
+					}
+				case "font":
+					{
+						if (wc == null)
+							throw new CodeEE("<" + tag + ">タグに属性が設定されていません");
+						HtmlAnalzeStateFontTag font = new HtmlAnalzeStateFontTag();
+						while (!wc.EOL)
+						{
+							word = wc.Current as IdentifierWord;
+							wc.ShiftNext();
+							OperatorWord op = wc.Current as OperatorWord;
+							wc.ShiftNext();
+							LiteralStringWord attr = wc.Current as LiteralStringWord;
+							wc.ShiftNext();
+							if (word == null || op == null || op.Code != OperatorCode.Assignment || attr == null)
+								goto error;
+							string attrValue = Unescape(attr.Str);
+							switch (word.Code.ToLower())
+							{
+								case "color":
+									if (font.Color >= 0)
+										throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
+									font.Color = stringToColorInt32(attrValue);
+									break;
+								case "bcolor":
+									if (font.BColor >= 0)
+										throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
+									font.BColor = stringToColorInt32(attrValue);
+									break;
+								case "face":
+									if (font.FontName != null)
+										throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
+									font.FontName = attrValue;
+									break;
+								//case "pos":
+								//	{
+								//		//throw new NotImplCodeEE();
+								//		if (font.PointXisLocked)
+								//			throw new CodeEE("<" + tag + ">タグに" + word.Code + "属性が2度以上指定されています");
+								//		int pos = 0;
+								//		if (!int.TryParse(attrValue, out pos))
+								//			throw new CodeEE("<font>タグのpos属性の属性値が数値として解釈できません");
+								//		font.PointX = pos;
+								//		font.PointXisLocked = true;
+								//		break;
+								//	}
+								default:
+								throw new CodeEE("<" + tag + ">タグの属性名" + word.Code + "は解釈できません");
+							}
+						}
+						//他のfontタグの内側であるなら未設定項目については外側のfontタグの設定を受け継ぐ(posは除く)
+						if (state.FonttagList.Count > 0)
+						{
+							HtmlAnalzeStateFontTag oldFont = state.FonttagList[state.FonttagList.Count - 1];
+							if (font.Color < 0)
+								font.Color = oldFont.Color;
+							if (font.BColor < 0)
+								font.BColor = oldFont.BColor;
+							if (font.FontName == null)
+								font.FontName = oldFont.FontName;
+						}
+						state.FonttagList.Add(font);
+						return null;
+					}
+				default:
+					goto error;
+			}
+
+
+		error:
+			throw new CodeEE("html文字列\"" + st.RowString + "\"のタグ解析中にエラーが発生しました");
+		}
+
+		private static int stringToColorInt32(string str)
+		{
+			if(str.Length == 0)
+				throw new CodeEE("色を表す単語又は#RRGGBB値が必要です");
+			int i = 0;
+			if (str[0] == '#')
+			{
+				string colorvalue = str.Substring(1);
+				try
+				{
+					i = Convert.ToInt32(colorvalue, 16);
+					if (i < 0 || i > 0xFFFFFF)
+						throw new CodeEE(colorvalue + "は適切な色指定の範囲外です");
+				}
+				catch
+				{
+					throw new CodeEE(colorvalue + "は数値として解釈できません");
+				}
+			}
+			else
+			{
+				Color color = Color.FromName(str);
+				if (color.A == 0)//色名として解釈失敗 エラー確定
+				{
+					if(str.Equals("transparent", StringComparison.OrdinalIgnoreCase))
+						throw new CodeEE("無色透明(Transparent)は色として指定できません");
+					try
+					{
+						i = Convert.ToInt32(str, 16);
+					}
+					catch//16進数でもない
+					{
+						throw new CodeEE("指定された色名\"" + str + "\"は無効な色名です");
+					}
+					//#RRGGBBを意図したのかもしれない
+					throw new CodeEE("指定された色名\"" + str + "\"は無効な色名です(16進数で色を指定する場合には数値の前に#が必要です)");
+				}
+				i = color.R * 0x10000 + color.G * 0x100 + color.B;
+			}
+			return i;
+		}
+
+	}
+}

+ 543 - 0
NTERA/Game/Display/PrintStringBuffer.cs

@@ -0,0 +1,543 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Text;
+using MinorShift.Emuera;
+using MinorShift.Emuera.Sub;
+using NTERA.Interop;
+
+namespace NTERA.Game.Display
+{
+	/*
+	 * ConsoleStyledString = string + StringStyle
+	 * ConsoleButtonString = (ConsoleStyledString) * n + ButtonValue
+	 * ConsoleDisplayLine = (ConsoleButtonString) * n
+	 * PrintStringBufferはERBのPRINT命令からConsoleDisplayLineを作る
+	*/
+
+	/// <summary>
+	/// PRINT命令を貯める&最終的に解決するクラス
+	/// </summary>
+	internal sealed class PrintStringBuffer
+	{
+		public PrintStringBuffer(IConsole parent)
+		{
+			this.parent = parent;
+		}
+		readonly IConsole parent;
+		StringBuilder builder = new StringBuilder();
+		List<AConsoleDisplayPart> m_stringList = new List<AConsoleDisplayPart>();
+		StringStyle lastStringStyle;
+		List<ConsoleButtonString> m_buttonList = new List<ConsoleButtonString>();
+
+		public int BufferStrLength
+		{
+			get
+			{
+				int length = 0;
+				foreach (AConsoleDisplayPart css in m_stringList)
+				{
+					if (css is ConsoleStyledString)
+						length += css.Str.Length;
+					else
+						length += 1;
+				}
+				return length;
+			}
+		}
+
+		public void Append(AConsoleDisplayPart part)
+		{
+			if (builder.Length != 0)
+			{
+				m_stringList.Add(new ConsoleStyledString(builder.ToString(), lastStringStyle));
+				builder.Remove(0, builder.Length);
+			}
+			m_stringList.Add(part);
+		}
+
+		public void Append(string str, StringStyle style)
+		{
+			Append(str, style, false);
+		}
+
+		public void Append(string str, StringStyle style, bool force_button)
+		{
+			if (BufferStrLength > 2000)
+				return;
+			if (force_button)
+				fromCssToButton();
+			if ((builder.Length == 0) || (lastStringStyle == style))
+			{
+				if (builder.Length > 2000)
+					return;
+				if (builder.Length + str.Length > 2000)
+					str = str.Substring(0, 2000 - builder.Length) + "※※※バッファーの文字数が2000字(全角1000字)を超えています。これ以降は表示できません※※※";
+				builder.Append(str);
+				lastStringStyle = style;
+			}
+			else
+			{
+				m_stringList.Add(new ConsoleStyledString(builder.ToString(), lastStringStyle));
+				builder.Remove(0, builder.Length);
+				builder.Append(str);
+				lastStringStyle = style;
+			}
+			if (force_button)
+				fromCssToButton();
+		}
+
+		public void AppendButton(string str, StringStyle style, string input)
+		{
+			fromCssToButton();
+			m_stringList.Add(new ConsoleStyledString(str, style));
+			if (m_stringList.Count == 0)
+				return;
+			m_buttonList.Add(createButton(m_stringList, input));
+			m_stringList.Clear();
+		}
+
+		public void AppendButton(string str, StringStyle style, long input)
+		{
+			fromCssToButton();
+			m_stringList.Add(new ConsoleStyledString(str, style));
+			if (m_stringList.Count == 0)
+				return;
+			m_buttonList.Add(createButton(m_stringList, input));
+			m_stringList.Clear();
+		}
+
+        public void AppendButton(ConsoleButtonString cbs, StringStyle style)
+        {
+            fromCssToButton();
+            m_stringList.Add(new ConsoleStyledString(cbs.ToString(), style));
+            if (m_stringList.Count == 0)
+                return;
+            m_buttonList.Add(cbs);
+            m_stringList.Clear();
+        }
+
+        public void AppendPlainText(string str, StringStyle style)
+		{
+			fromCssToButton();
+			m_stringList.Add(new ConsoleStyledString(str, style));
+			if (m_stringList.Count == 0)
+				return;
+			m_buttonList.Add(createPlainButton(m_stringList));
+			m_stringList.Clear();
+		}
+
+		public bool IsEmpty => ((m_buttonList.Count == 0) && (builder.Length == 0) && (m_stringList.Count == 0));
+
+		public override string ToString()
+		{
+			StringBuilder buf = new StringBuilder();
+			foreach (ConsoleButtonString button in m_buttonList)
+				buf.Append(button);
+			foreach (AConsoleDisplayPart css in m_stringList)
+				buf.Append(css.Str);
+			buf.Append(builder);
+			return buf.ToString();
+		}
+
+		public ConsoleDisplayLine AppendAndFlushErrButton(string str, StringStyle style, string input, ScriptPosition pos, StringMeasure sm)
+		{
+			fromCssToButton();
+			m_stringList.Add(new ConsoleStyledString(str, style));
+			if (m_stringList.Count == 0)
+				return null;
+			m_buttonList.Add(createButton(m_stringList, input, pos));
+			m_stringList.Clear();
+			return FlushSingleLine(sm, false);
+		}
+
+		public ConsoleDisplayLine FlushSingleLine(StringMeasure stringMeasure, bool temporary)
+		{
+			fromCssToButton();
+			setWidthToButtonList(m_buttonList, stringMeasure, true);
+			ConsoleButtonString[] dispLineButtonArray = new ConsoleButtonString[m_buttonList.Count];
+			m_buttonList.CopyTo(dispLineButtonArray);
+			ConsoleDisplayLine line = new ConsoleDisplayLine(dispLineButtonArray, true, temporary);
+			clearBuffer();
+			return line;
+		}
+
+		public ConsoleDisplayLine[] Flush(StringMeasure stringMeasure, bool temporary)
+		{
+			fromCssToButton();
+			ConsoleDisplayLine[] ret = ButtonsToDisplayLines(m_buttonList, stringMeasure, false, temporary);
+			clearBuffer();
+			return ret;
+		}
+
+		private static ConsoleDisplayLine m_buttonsToDisplayLine(List<ConsoleButtonString> lineButtonList, bool firstLine, bool temporary)
+		{
+			ConsoleButtonString[] dispLineButtonArray = new ConsoleButtonString[lineButtonList.Count];
+			lineButtonList.CopyTo(dispLineButtonArray);
+			lineButtonList.Clear();
+			return new ConsoleDisplayLine(dispLineButtonArray, firstLine, temporary);
+		}
+
+		public static ConsoleDisplayLine[] ButtonsToDisplayLines(List<ConsoleButtonString> buttonList, StringMeasure stringMeasure, bool nobr, bool temporary)
+		{
+			if (buttonList.Count == 0)
+				return new ConsoleDisplayLine[0];
+			setWidthToButtonList(buttonList, stringMeasure, nobr);
+			List<ConsoleDisplayLine> lineList = new List<ConsoleDisplayLine>();
+			List<ConsoleButtonString> lineButtonList = new List<ConsoleButtonString>();
+			int windowWidth = Config.DrawableWidth;
+			bool firstLine = true;
+			for (int i = 0; i < buttonList.Count; i++)
+			{
+				if (buttonList[i] == null)
+				{//強制改行フラグ
+					lineList.Add(m_buttonsToDisplayLine(lineButtonList, firstLine, temporary));
+					firstLine = false;
+					buttonList.RemoveAt(i);
+					i--;
+					continue;
+				}
+				if (nobr || ((buttonList[i].PointX + buttonList[i].Width <= windowWidth)))
+				{//改行不要モードであるか表示可能領域に収まるならそのままでよい
+					lineButtonList.Add(buttonList[i]);
+					continue;
+				}
+				//新しい表示行を作る
+
+				//ボタンを分割するか?
+				//「ボタンの途中で行を折りかえさない」がfalseなら分割する
+				//このボタンが単体で表示可能領域を上回るなら分割必須
+				//クリック可能なボタンでないなら分割する。ただし「ver1739以前の非ボタン折り返しを再現する」ならクリックの可否を区別しない
+				if ((!Config.ButtonWrap) || (lineButtonList.Count == 0) || (!buttonList[i].IsButton && !Config.CompatiLinefeedAs1739))
+				{//ボタン分割する
+					int divIndex = getDivideIndex(buttonList[i], stringMeasure);
+					if (divIndex > 0)
+					{
+						ConsoleButtonString newButton = buttonList[i].DivideAt(divIndex, stringMeasure);
+						//newButton.CalcPointX(buttonList[i].PointX + buttonList[i].Width);
+						buttonList.Insert(i + 1, newButton);
+						lineButtonList.Add(buttonList[i]);
+						i++;
+					}
+					else if (divIndex == 0 && (lineButtonList.Count > 0))
+					{//まるごと次の行に送る
+					}
+					else//分割できない要素のみで構成されたボタンは分割できない
+					{
+						lineButtonList.Add(buttonList[i]);
+						continue;
+					}
+				}
+				lineList.Add(m_buttonsToDisplayLine(lineButtonList, firstLine, temporary));
+				firstLine = false;
+				//位置調整
+//				shiftX = buttonList[i].PointX;
+				int pointX = 0;
+				for (int j = i; j < buttonList.Count; j++)
+				{
+					if (buttonList[j] == null)//強制改行を挟んだ後は調整無用
+						break;
+					buttonList[j].CalcPointX(pointX);
+					pointX += buttonList[j].Width;
+				}
+				i--;//buttonList[i]は新しい行に含めないので次の行のために再検討する必要がある(直後のi++と相殺)
+			}
+			if (lineButtonList.Count > 0)
+			{
+				lineList.Add(m_buttonsToDisplayLine(lineButtonList, firstLine, temporary));
+			}
+			ConsoleDisplayLine[] ret = new ConsoleDisplayLine[lineList.Count];
+			lineList.CopyTo(ret);
+			return ret;
+		}
+
+		/// <summary>
+		/// 1810beta003新規 マークアップ用 Append とFlushを同時にやる
+		/// </summary>
+		/// <param name="str"></param>
+		/// <param name="stringMeasure"></param>
+		/// <returns></returns>
+		public ConsoleDisplayLine[] PrintHtml(string str, StringMeasure stringMeasure)
+		{
+			throw new NotImplementedException();
+		}
+
+		#region Flush用privateメソッド
+
+		private void clearBuffer()
+		{
+			builder.Remove(0, builder.Length);
+			m_stringList.Clear();
+			m_buttonList.Clear();
+		}
+
+		/// <summary>
+		/// cssListをbuttonに変換し、buttonListに追加。
+		/// この時点ではWidthなどは考えない。
+		/// </summary>
+		private void fromCssToButton()
+		{
+			if (builder.Length != 0)
+			{
+				m_stringList.Add(new ConsoleStyledString(builder.ToString(), lastStringStyle));
+				builder.Remove(0, builder.Length);
+			}
+			if (m_stringList.Count == 0)
+				return;
+			m_buttonList.AddRange(createButtons(m_stringList));
+			m_stringList.Clear();
+		}
+
+		/// <summary>
+		/// 物理行を1つのボタンへ。
+		/// </summary>
+		/// <returns></returns>
+		private ConsoleButtonString createButton(List<AConsoleDisplayPart> cssList, string input)
+		{
+			AConsoleDisplayPart[] cssArray = new AConsoleDisplayPart[cssList.Count];
+			cssList.CopyTo(cssArray);
+			cssList.Clear();
+			return new ConsoleButtonString(parent, cssArray, input);
+		}
+		private ConsoleButtonString createButton(List<AConsoleDisplayPart> cssList, string input, ScriptPosition pos)
+		{
+			AConsoleDisplayPart[] cssArray = new AConsoleDisplayPart[cssList.Count];
+			cssList.CopyTo(cssArray);
+			cssList.Clear();
+			return new ConsoleButtonString(parent, cssArray, input, pos);
+		}
+		private ConsoleButtonString createButton(List<AConsoleDisplayPart> cssList, long input)
+		{
+			AConsoleDisplayPart[] cssArray = new AConsoleDisplayPart[cssList.Count];
+			cssList.CopyTo(cssArray);
+			cssList.Clear();
+			return new ConsoleButtonString(parent, cssArray, input);
+		}
+		private ConsoleButtonString createPlainButton(List<AConsoleDisplayPart> cssList)
+		{
+			AConsoleDisplayPart[] cssArray = new AConsoleDisplayPart[cssList.Count];
+			cssList.CopyTo(cssArray);
+			cssList.Clear();
+			return new ConsoleButtonString(parent, cssArray);
+		}
+
+		/// <summary>
+		/// 物理行をボタン単位に分割。引数のcssListの内容は変更される場合がある。
+		/// </summary>
+		/// <returns></returns>
+		private ConsoleButtonString[] createButtons(List<AConsoleDisplayPart> cssList)
+		{
+			StringBuilder buf = new StringBuilder();
+			for (int i = 0; i < cssList.Count; i++)
+			{
+				buf.Append(cssList[i].Str);
+			}
+			List<ButtonPrimitive> bpList = ButtonStringCreator.SplitButton(buf.ToString());
+			ConsoleButtonString[] ret = new ConsoleButtonString[bpList.Count];
+			AConsoleDisplayPart[] cssArray = null;
+			if (ret.Length == 1)
+			{
+				cssArray = new AConsoleDisplayPart[cssList.Count];
+				cssList.CopyTo(cssArray);
+				if (bpList[0].CanSelect)
+					ret[0] = new ConsoleButtonString(parent, cssArray, bpList[0].Input);
+				else
+					ret[0] = new ConsoleButtonString(parent, cssArray);
+				return ret;
+			}
+			int cssStartCharIndex = 0;
+			int buttonEndCharIndex = 0;
+			int cssIndex = 0;
+			List<AConsoleDisplayPart> buttonCssList = new List<AConsoleDisplayPart>();
+			for (int i = 0; i < ret.Length; i++)
+			{
+				ButtonPrimitive bp = bpList[i];
+				buttonEndCharIndex += bp.Str.Length;
+				while (true)
+				{
+					if (cssIndex >= cssList.Count)
+						break;
+					AConsoleDisplayPart css = cssList[cssIndex];
+					if (cssStartCharIndex + css.Str.Length >= buttonEndCharIndex)
+					{//ボタンの終端を発見
+						int used = buttonEndCharIndex - cssStartCharIndex;
+						if (used > 0 && css.CanDivide)
+						{//cssの区切りの途中でボタンの区切りがある。
+							
+							ConsoleStyledString newCss = ((ConsoleStyledString)css).DivideAt(used);
+							if (newCss != null)
+							{
+								cssList.Insert(cssIndex + 1, newCss);
+								newCss.PointX = css.PointX + css.Width;
+							}
+						}
+						buttonCssList.Add(css);
+						cssStartCharIndex += css.Str.Length;
+						cssIndex++;
+						break;
+					}
+					//ボタンの終端はまだ先。
+					buttonCssList.Add(css);
+					cssStartCharIndex += css.Str.Length;
+					cssIndex++;
+				}
+				cssArray = new AConsoleDisplayPart[buttonCssList.Count];
+				buttonCssList.CopyTo(cssArray);
+				if (bp.CanSelect)
+					ret[i] = new ConsoleButtonString(parent, cssArray, bp.Input);
+				else
+					ret[i] = new ConsoleButtonString(parent, cssArray);
+				buttonCssList.Clear();
+			}
+			return ret;
+
+		}
+
+
+		//stringListにPointX、Widthを追加
+		public static void setWidthToButtonList(List<ConsoleButtonString> buttonList, StringMeasure stringMeasure, bool nobr)
+		{
+			int pointX = 0;
+			int count = buttonList.Count;
+			float subPixel = 0;
+			for (int i = 0; i < buttonList.Count; i++)
+			{
+				ConsoleButtonString button = buttonList[i];
+				if (button == null)
+				{//改行フラグ
+					pointX = 0;
+					continue;
+				}
+				button.CalcWidth(stringMeasure, subPixel);
+				button.CalcPointX(pointX);
+				pointX = button.PointX + button.Width;
+				if (button.PointXisLocked)
+					subPixel = 0;
+				//pointX += button.Width;
+				subPixel = button.XsubPixel;
+			}
+
+			//1815 バグバグなのでコメントアウト Width測定の省略はいずれやりたい
+			////1815 alignLeft, nobrを前提にした新方式
+			////PointXの直接指定を可能にし、Width測定を一部省略
+			//ConsoleStyledString lastCss = null;
+			//for (int i = 0; i < buttonList.Count; i++)
+			//{
+			//    ConsoleButtonString button = buttonList[i];
+			//    if (button == null)
+			//    {//改行フラグ
+			//        pointX = 0;
+			//        lastCss = null;
+			//        continue;
+			//    }
+			//    for (int j = 0; j < button.StrArray.Length; j++)
+			//    {
+			//        ConsoleStyledString css = button.StrArray[j];
+			//        if (css.PointXisLocked)//位置固定フラグ
+			//        {//位置固定なら前のcssのWidth測定を省略
+			//            pointX = css.PointX;
+			//            if (lastCss != null)
+			//            {
+			//                lastCss.Width = css.PointX - lastCss.PointX;
+			//                if (lastCss.Width < 0)
+			//                    lastCss.Width = 0;
+			//            }
+			//        }
+			//        else
+			//        {
+			//            if (lastCss != null)
+			//            {
+			//                lastCss.SetWidth(stringMeasure);
+			//                pointX += lastCss.Width;
+			//            }
+			//            css.PointX = pointX;
+			//        }
+			//    }
+			//}
+			////ConsoleButtonStringの位置・幅を決定(クリック可能域の決定のために必要)
+			//for (int i = 0; i < buttonList.Count; i++)
+			//{
+			//    ConsoleButtonString button = buttonList[i];
+			//    if (button == null || button.StrArray.Length == 0)
+			//        continue;
+			//    button.PointX = button.StrArray[0].PointX;
+			//    lastCss = button.StrArray[button.StrArray.Length - 1];
+			//    if (lastCss.Width >= 0)
+			//        button.Width = lastCss.PointX - button.PointX + lastCss.Width;
+			//    else if (i >= buttonList.Count - 1 || buttonList[i+1] == null || buttonList[i+1].StrArray.Length == 0)//行末
+			//        button.Width = Config.WindowX;//右端のボタンについては右側全部をボタン領域にしてしまう
+			//    else
+			//        button.Width = buttonList[i+1].StrArray[0].PointX - button.PointX;
+			//    if (button.Width < 0)
+			//        button.Width = 0;//pos指定次第ではクリック不可能なボタンができてしまう。まあ仕方ない
+			//}
+		}
+
+		private static int getDivideIndex(ConsoleButtonString button, StringMeasure sm)
+		{
+			AConsoleDisplayPart divCss = null;
+			int pointX = button.PointX;
+			int strLength = 0;
+			int index = 0;
+			foreach (AConsoleDisplayPart css in button.StrArray)
+			{
+				if (pointX + css.Width > Config.DrawableWidth)
+				{
+					if (index == 0 && !css.CanDivide)
+						continue;
+					divCss = css;
+					break;
+				}
+				index++;
+				strLength += css.Str.Length;
+				pointX += css.Width;
+			}
+			if (divCss != null)
+			{
+				int cssDivIndex = getDivideIndex(divCss, sm);
+				if (cssDivIndex > 0)
+					strLength += cssDivIndex;
+			}
+			return strLength;
+		}
+
+		private static int getDivideIndex(AConsoleDisplayPart part, StringMeasure sm)
+		{
+			if (!part.CanDivide)
+				return -1;
+			ConsoleStyledString css = part as ConsoleStyledString;
+			if (part == null)
+				return -1;
+			int widthLimit = Config.DrawableWidth - css.PointX;
+			string str = css.Str;
+			Font font = css.Font;
+			int point = 0;
+			int highLength = str.Length;//widthLimitを超える最低の文字index(文字数-1)。
+			int lowLength = 0;//超えない最大の文字index。
+			//int i = (int)(widthLimit / fontDisplaySize);//およその文字数を推定
+			//if (i > str.Length - 1)//配列の外を参照しないように。
+			//	i = str.Length - 1;
+			int i = lowLength;//およその文字数を推定←やめた
+
+			string test = null;
+			while ((highLength - lowLength) > 1)//差が一文字以下になるまで繰り返す。
+			{
+				test = str.Substring(0, i);
+				point = sm.GetDisplayLength(test, font);
+				if (point <= widthLimit)//サイズ内ならlowLengthを更新。文字数を増やす。
+				{
+					lowLength = i;
+					i++;
+				}
+				else//サイズ外ならhighLengthを更新。文字数を減らす。
+				{
+					highLength = i;
+					i--;
+				}
+			}
+			return lowLength;
+		}
+		#endregion
+
+	}
+}

+ 87 - 0
NTERA/Game/Display/StringMeasure.cs

@@ -0,0 +1,87 @@
+using System;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Windows.Forms;
+using MinorShift.Emuera;
+using MinorShift._Library;
+
+namespace NTERA.Game.Display
+{
+
+	/// <summary>
+	/// テキスト長計測装置
+	/// 1819 必要になるたびにCreateGraphicsする方式をやめてあらかじめGraphicsを用意しておくことにする
+	/// </summary>
+	public sealed class StringMeasure : IDisposable
+	{
+		public StringMeasure()
+		{
+			textDrawingMode = Config.TextDrawingMode;
+			layoutSize = new Size(Config.WindowX * 2, Config.LineHeight);
+			layoutRect = new RectangleF(0, 0, Config.WindowX * 2, Config.LineHeight);
+			fontDisplaySize = Config.Font.Size / 2 * 1.04f;//実際には指定したフォントより若干幅をとる?
+			//bmp = new Bitmap(Config.WindowX, Config.LineHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+			bmp = new Bitmap(16, 16, PixelFormat.Format32bppArgb);
+			graph = Graphics.FromImage(bmp);
+			if (textDrawingMode == TextDrawingMode.WINAPI)
+				GDI.GdiMesureTextStart(graph);
+		}
+
+		readonly TextDrawingMode textDrawingMode;
+		readonly StringFormat sf = new StringFormat(StringFormatFlags.MeasureTrailingSpaces);
+		readonly CharacterRange[] ranges = { new CharacterRange(0, 1) };
+		readonly Size layoutSize;
+		readonly RectangleF layoutRect;
+		readonly float fontDisplaySize;
+
+		readonly Graphics graph;
+		readonly Bitmap bmp;
+
+		public int GetDisplayLength(string s, Font font)
+		{
+			if (string.IsNullOrEmpty(s))
+				return 0;
+			if (textDrawingMode == TextDrawingMode.GRAPHICS)
+			{
+				if (s.Contains("\t"))
+					s = s.Replace("\t", "        ");
+				ranges[0].Length = s.Length;
+				//CharacterRange[] ranges = new CharacterRange[] { new CharacterRange(0, s.Length) };
+				sf.SetMeasurableCharacterRanges(ranges);
+				Region[] regions = graph.MeasureCharacterRanges(s, font, layoutRect, sf);
+				RectangleF rectF = regions[0].GetBounds(graph);
+				//return (int)rectF.Width;//プロポーショナルでなくても数ピクセルずれる
+				return (int)((int)((rectF.Width - 1) / fontDisplaySize + 0.95f) * fontDisplaySize);
+			}
+
+			if (textDrawingMode == TextDrawingMode.TEXTRENDERER)
+			{
+				Size size = TextRenderer.MeasureText(graph, s, font, layoutSize, TextFormatFlags.NoPadding | TextFormatFlags.NoPrefix);
+				//Size size = TextRenderer.MeasureText(g, s, StaticConfig.Font);
+				return size.Width;
+			}
+			else// if (StaticConfig.TextDrawingMode == TextDrawingMode.WINAPI)
+			{
+				Size size = GDI.MeasureText(s, font);
+				return size.Width;
+			}
+			//来るわけがない
+			//else
+			//    throw new ExeEE("描画モード不明");
+		}
+
+
+		bool disposed;
+		public void Dispose()
+		{
+			if (disposed)
+				return;
+			disposed = true;
+			if (textDrawingMode == TextDrawingMode.WINAPI)
+				GDI.GdiMesureTextEnd(graph);
+			graph.Dispose();
+			bmp.Dispose();
+            sf.Dispose();
+		}
+	}
+}

+ 1446 - 0
NTERA/Game/GameData/ConstantData.cs

@@ -0,0 +1,1446 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Media;
+using System.Reflection;
+using System.Text;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.Sub;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera.GameData
+{
+	//難読化用属性。enum.ToString()やenum.Parse()を行うなら(Exclude=true)にすること。
+	[Obfuscation(Exclude = false)]
+	internal enum CharacterStrData
+	{
+		NAME = 0,
+		CALLNAME = 1,
+		NICKNAME = 2,
+		MASTERNAME = 3,
+		CSTR = 4
+	}
+	
+	//難読化用属性。enum.ToString()やenum.Parse()を行うなら(Exclude=true)にすること。
+	[Obfuscation(Exclude = false)]
+	internal enum CharacterIntData
+	{
+		BASE = 0,
+		ABL = 1,
+		TALENT = 2,
+		MARK = 3,
+		EXP = 4,
+		RELATION = 5,
+		CFLAG = 6,
+		EQUIP = 7,
+		JUEL = 8
+		
+	}
+	
+	internal sealed class ConstantData
+	{
+
+		private const int ablIndex = (int)(VariableCode.ABLNAME & VariableCode.__LOWERCASE__);
+		private const int expIndex = (int)(VariableCode.EXPNAME & VariableCode.__LOWERCASE__);
+		private const int talentIndex = (int)(VariableCode.TALENTNAME & VariableCode.__LOWERCASE__);
+		private const int paramIndex = (int)(VariableCode.PALAMNAME & VariableCode.__LOWERCASE__);
+		private const int trainIndex = (int)(VariableCode.TRAINNAME & VariableCode.__LOWERCASE__);
+		private const int markIndex = (int)(VariableCode.MARKNAME & VariableCode.__LOWERCASE__);
+		private const int itemIndex = (int)(VariableCode.ITEMNAME & VariableCode.__LOWERCASE__);
+		private const int baseIndex = (int)(VariableCode.BASENAME & VariableCode.__LOWERCASE__);
+		private const int sourceIndex = (int)(VariableCode.SOURCENAME & VariableCode.__LOWERCASE__);
+		private const int exIndex = (int)(VariableCode.EXNAME & VariableCode.__LOWERCASE__);
+		private const int strIndex = (int)(VariableCode.__DUMMY_STR__ & VariableCode.__LOWERCASE__);
+		private const int equipIndex = (int)(VariableCode.EQUIPNAME & VariableCode.__LOWERCASE__);
+		private const int tequipIndex = (int)(VariableCode.TEQUIPNAME & VariableCode.__LOWERCASE__);
+		private const int flagIndex = (int)(VariableCode.FLAGNAME & VariableCode.__LOWERCASE__);
+		private const int tflagIndex = (int)(VariableCode.TFLAGNAME & VariableCode.__LOWERCASE__);
+		private const int cflagIndex = (int)(VariableCode.CFLAGNAME & VariableCode.__LOWERCASE__);
+		private const int tcvarIndex = (int)(VariableCode.TCVARNAME & VariableCode.__LOWERCASE__);
+		private const int cstrIndex = (int)(VariableCode.CSTRNAME & VariableCode.__LOWERCASE__);
+		private const int stainIndex = (int)(VariableCode.STAINNAME & VariableCode.__LOWERCASE__);
+		private const int cdflag1Index = (int)(VariableCode.CDFLAGNAME1 & VariableCode.__LOWERCASE__);
+		private const int cdflag2Index = (int)(VariableCode.CDFLAGNAME2 & VariableCode.__LOWERCASE__);
+		private const int strnameIndex = (int)(VariableCode.STRNAME & VariableCode.__LOWERCASE__);
+		private const int tstrnameIndex = (int)(VariableCode.TSTRNAME & VariableCode.__LOWERCASE__);
+		private const int savestrnameIndex = (int)(VariableCode.SAVESTRNAME & VariableCode.__LOWERCASE__);
+		private const int globalIndex = (int)(VariableCode.GLOBALNAME & VariableCode.__LOWERCASE__);
+		private const int globalsIndex = (int)(VariableCode.GLOBALSNAME & VariableCode.__LOWERCASE__);
+		private const int countNameCsv = (int)VariableCode.__COUNT_CSV_STRING_ARRAY_1D__;
+
+        public int[] MaxDataList = new int[countNameCsv];
+		List<VariableCode> changedCode = new List<VariableCode>();
+		
+		public int[] VariableIntArrayLength;
+		public int[] VariableStrArrayLength;
+		public Int64[] VariableIntArray2DLength;
+		public Int64[] VariableStrArray2DLength;
+		public Int64[] VariableIntArray3DLength;
+		public Int64[] VariableStrArray3DLength;
+		public int[] CharacterIntArrayLength;
+		public int[] CharacterStrArrayLength;
+		public Int64[] CharacterIntArray2DLength;
+		public Int64[] CharacterStrArray2DLength;
+		public Translation tranls;
+        // JVN: Keep track if loading PARAM or PALAM.CSV
+        private static bool canLoadParam;
+
+
+        private readonly GameBase gamebase;
+		private string[][] names = new string[(int)VariableCode.__COUNT_CSV_STRING_ARRAY_1D__][];
+		private Dictionary<string, int>[] nameToIntDics = new Dictionary<string, int>[(int)VariableCode.__COUNT_CSV_STRING_ARRAY_1D__];
+		private Dictionary<string, int> relationDic = new Dictionary<string, int>();
+		public string[] GetCsvNameList(VariableCode code)
+		{
+			return names[(int)(code & VariableCode.__LOWERCASE__)];
+		}
+
+		public Int64[] ItemPrice;
+		
+		private readonly List<CharacterTemplate> CharacterTmplList;
+		private IConsole output;
+		
+		public ConstantData(GameBase gamebase)
+		{
+			this.gamebase = gamebase;
+			setDefaultArrayLength();
+
+			CharacterTmplList = new List<CharacterTemplate>();
+			useCompatiName = Config.CompatiCALLNAME;
+		}
+
+		readonly bool useCompatiName;
+
+		private void setDefaultArrayLength()
+		{
+			MaxDataList[ablIndex] = 100;
+			MaxDataList[talentIndex] = 1000;
+			MaxDataList[expIndex] = 100;
+			MaxDataList[markIndex] = 100;
+			MaxDataList[trainIndex] = 1000;
+			MaxDataList[paramIndex] = 200;
+			MaxDataList[itemIndex] = 1000;
+			MaxDataList[baseIndex] = 100;
+			MaxDataList[sourceIndex] = 1000;
+			MaxDataList[exIndex] = 100;
+			MaxDataList[equipIndex] = 100;
+			MaxDataList[tequipIndex] = 100;
+			MaxDataList[flagIndex] = 10000;
+			MaxDataList[tflagIndex] = 1000;
+			MaxDataList[cflagIndex] = 1000;
+			MaxDataList[tcvarIndex] = 100;
+			MaxDataList[cstrIndex] = 100;
+			MaxDataList[stainIndex] = 1000;
+			MaxDataList[strIndex] = 20000;
+			MaxDataList[cdflag1Index] = 1;
+			MaxDataList[cdflag2Index] = 1;
+			MaxDataList[strnameIndex] = 20000;
+			MaxDataList[tstrnameIndex] = 100;
+			MaxDataList[savestrnameIndex] = 100;
+			MaxDataList[globalIndex] = 1000;
+			MaxDataList[globalsIndex] = 100;
+
+			VariableIntArrayLength = new int[(int)VariableCode.__COUNT_INTEGER_ARRAY__];
+			VariableStrArrayLength = new int[(int)VariableCode.__COUNT_STRING_ARRAY__];
+			VariableIntArray2DLength = new Int64[(int)VariableCode.__COUNT_INTEGER_ARRAY_2D__];
+			VariableStrArray2DLength = new Int64[(int)VariableCode.__COUNT_STRING_ARRAY_2D__];
+			VariableIntArray3DLength = new Int64[(int)VariableCode.__COUNT_INTEGER_ARRAY_3D__];
+			VariableStrArray3DLength = new Int64[(int)VariableCode.__COUNT_STRING_ARRAY_3D__];
+			CharacterIntArrayLength = new int[(int)VariableCode.__COUNT_CHARACTER_INTEGER_ARRAY__];
+			CharacterStrArrayLength = new int[(int)VariableCode.__COUNT_CHARACTER_STRING_ARRAY__];
+			CharacterIntArray2DLength = new Int64[(int)VariableCode.__COUNT_CHARACTER_INTEGER_ARRAY_2D__];
+			CharacterStrArray2DLength = new Int64[(int)VariableCode.__COUNT_CHARACTER_STRING_ARRAY_2D__];
+			for (int i = 0; i < VariableIntArrayLength.Length; i++)
+				VariableIntArrayLength[i] = 1000;
+			VariableIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.FLAG)] = 10000;
+			VariableIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.ITEMPRICE)] = MaxDataList[itemIndex];
+
+			VariableIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.RANDDATA)] = 625;
+
+			for (int i = 0; i < VariableStrArrayLength.Length; i++)
+				VariableStrArrayLength[i] = 100;
+			VariableStrArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.STR)] = MaxDataList[strIndex];
+
+			for (int i = 0; i < VariableIntArray2DLength.Length; i++)
+				VariableIntArray2DLength[i] = (100L << 32) + 100L;
+			for (int i = 0; i < VariableStrArray2DLength.Length; i++)
+				VariableStrArray2DLength[i] = (100L << 32) + 100L;
+
+			for (int i = 0; i < VariableIntArray3DLength.Length; i++)
+				VariableIntArray3DLength[i] = (100L << 40) + (100L << 20) + 100L;
+			for (int i = 0; i < VariableStrArray3DLength.Length; i++)
+				VariableStrArray3DLength[i] = (100L << 40) + (100L << 20) + 100L;
+
+			for (int i = 0; i < CharacterIntArrayLength.Length; i++)
+				CharacterIntArrayLength[i] = 100;
+			CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.TALENT)] = 1000;
+			CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.CFLAG)] = 1000;
+			CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.JUEL)] = 200;
+			CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.GOTJUEL)] = 200;
+
+			for (int i = 0; i < CharacterStrArrayLength.Length; i++)
+				CharacterStrArrayLength[i] = 100;
+
+			for (int i = 0; i < CharacterIntArray2DLength.Length; i++)
+				CharacterIntArray2DLength[i] = (1L << 32) + 1L;
+			for (int i = 0; i < CharacterStrArray2DLength.Length; i++)
+				CharacterStrArray2DLength[i] = (1L << 32) + 1L;
+		}
+
+		private void loadVariableSizeData(string csvPath, bool disp)
+		{
+			if (!File.Exists(csvPath))
+				return;
+			EraStreamReader eReader = new EraStreamReader(false);
+			if (!eReader.Open(csvPath))
+			{
+				output.PrintError("Failed to open " + eReader.Filename);
+				return;
+			}
+			ScriptPosition position = null;
+			if (disp)
+				output.PrintSystemLine("Loading " + eReader.Filename + "...");
+			try
+			{
+				StringStream st = null;
+				while ((st = eReader.ReadEnabledLine()) != null)
+				{
+					position = new ScriptPosition(eReader.Filename, eReader.LineNo, st.RowString);
+					changeVariableSizeData(st.Substring(), position);
+				}
+				position = new ScriptPosition(eReader.Filename, -1, null);
+			}
+			catch
+			{
+                ShowParserError("An unexpected error has occured", position, 3);
+			}
+			finally
+			{
+				eReader.Close();
+			}
+			decideActualArraySize(position);
+		}
+
+
+		private void changeVariableSizeData(string line, ScriptPosition position)
+		{
+			string[] tokens = line.Split(',');
+			if (tokens.Length < 2)
+			{
+				ParserMediator.Warn("\",\" is required", position, 1);
+				return;
+			}
+			string idtoken = tokens[0].Trim();
+			VariableIdentifier id = VariableIdentifier.GetVariableId(idtoken);
+			if (id == null)
+			{
+				ParserMediator.Warn("The first value cannot be recognized as a variable name", position, 1);
+				return;
+			}
+			if ((!id.IsArray1D) && (!id.IsArray2D) && (!id.IsArray3D))
+			{
+				ParserMediator.Warn("Cannot change the size of a " + id + " variable that is not an array variable", position, 1);
+				return;
+			}
+			if ((id.IsCalc) || (id.Code == VariableCode.RANDDATA))
+			{
+				ParserMediator.Warn("Cannot change the size of a " + id + " variable", position, 1);
+				return;
+			}
+			int length = 0;
+			int length2 = 0;
+			int length3 = 0;
+			if (!int.TryParse(tokens[1], out length))
+			{
+				ParserMediator.Warn("The second value cannot be recognized as an integer value", position, 1);
+				return;
+			}
+            //1820a16 変数禁止指定 負の値を指定する
+			if (length <= 0)
+			{
+				if (length == 0)
+				{
+					ParserMediator.Warn("配列長に0は指定できません(変数を使用禁止にするには配列長に負の値を指定してください)", position, 2);
+					return;
+				}
+				if(!id.CanForbid)
+				{
+					ParserMediator.Warn("使用禁止にできない変数に対して負の配列長が指定されています", position, 2);
+					return;
+				}
+                if (tokens.Length > 2 && tokens[2].Length > 0 && tokens[2].Trim().Length > 0 && char.IsDigit((tokens[2].Trim())[0]))
+                {
+                    ParserMediator.Warn("一次元配列のサイズ指定に不必要なデータは無視されます", position, 0);
+                }
+				length = 0;
+				goto check1break;
+			}
+			if (id.IsArray1D)
+			{
+                if (tokens.Length > 2 && tokens[2].Length > 0 && tokens[2].Trim().Length > 0 && char.IsDigit((tokens[2].Trim())[0]))
+                {
+                    ParserMediator.Warn("一次元配列のサイズ指定に不必要なデータは無視されます", position, 0);
+                }
+				if (id.IsLocal && length < 1)
+				{
+					ParserMediator.Warn("ローカル変数のサイズを1未満にはできません", position, 1);
+					return;
+				}
+				if (!id.IsLocal && length < 100)
+				{
+					ParserMediator.Warn("ローカル変数でない一次元配列のサイズを100未満にはできません", position, 1);
+					return;
+				}
+				if (length > 1000000)
+				{
+					ParserMediator.Warn("一次元配列のサイズを1000000より大きくすることはできません", position, 1);
+					return;
+				}
+			}
+			else if (id.IsArray2D)
+			{
+				if (tokens.Length < 3)
+				{
+					ParserMediator.Warn("二次元配列のサイズ指定には2つの数値が必要です", position, 1);
+					return;
+				}
+                if (tokens.Length > 3 && tokens[3].Length > 0 && tokens[3].Trim().Length > 0 && char.IsDigit((tokens[3].Trim())[0]))
+                {
+                    ParserMediator.Warn("二次元配列のサイズ指定に不必要なデータは無視されます", position, 0);
+                }
+                if (!int.TryParse(tokens[2], out length2))
+				{
+					ParserMediator.Warn("三つ目の値を整数値として認識できません", position, 1);
+					return;
+				}
+				if ((length < 1) || (length2 < 1))
+				{
+					ParserMediator.Warn("配列サイズを1未満にはできません", position, 1);
+					return;
+				}
+				if ((length > 1000000) || (length2 > 1000000))
+				{
+					ParserMediator.Warn("配列サイズを1000000より大きくすることはできません", position, 1);
+					return;
+				}
+				if (length * length2 > 1000000)
+				{
+					ParserMediator.Warn("二次元配列の要素数は最大で100万個までです", position, 1);
+					return;
+				}
+			}
+			else if (id.IsArray3D)
+			{
+				if (tokens.Length < 4)
+				{
+					ParserMediator.Warn("三次元配列のサイズ指定には3つの数値が必要です", position, 1);
+					return;
+				}
+                if (tokens.Length > 4 && tokens[4].Length > 0 && tokens[4].Trim().Length > 0 && char.IsDigit((tokens[4].Trim())[0]))
+                {
+                    ParserMediator.Warn("三次元配列のサイズ指定に不必要なデータは無視されます", position, 0);
+                }
+                if (!int.TryParse(tokens[2], out length2))
+				{
+					ParserMediator.Warn("三つ目の値を整数値として認識できません", position, 1);
+					return;
+				}
+				if (!int.TryParse(tokens[3], out length3))
+				{
+					ParserMediator.Warn("四つ目の値を整数値として認識できません", position, 1);
+					return;
+				}
+				if ((length < 1) || (length2 < 1) || (length3 < 1))
+				{
+					ParserMediator.Warn("配列サイズを1未満にはできません", position, 1);
+					return;
+				}
+				//1802 サイズ保存の都合上、2^20超えるとバグる
+				if ((length > 1000000) || (length2 > 1000000) || (length3 > 1000000))
+				{
+					ParserMediator.Warn("配列サイズを1000000より大きくすることはできません", position, 1);
+					return;
+				}
+				if (length * length2 * length3 > 10000000)
+				{
+					ParserMediator.Warn("三次元配列の要素数は最大で1000万個までです", position, 1);
+					return;
+				}
+			}
+check1break:
+			switch (id.Code)
+			{
+				//1753a PALAMだけ仕様が違うのはかえって問題なので、変数と要素文字列配列数の同期は全部バックアウト
+				//基本的には旧来の処理に戻しただけ
+				case VariableCode.ITEMNAME:
+				case VariableCode.ITEMPRICE:
+					VariableIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.ITEMPRICE)] = length;
+					MaxDataList[itemIndex] = length;
+					break;
+				case VariableCode.STR:
+					VariableStrArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.STR)] = length;
+					MaxDataList[strIndex] = length;
+					break;
+				case VariableCode.ABLNAME:
+				case VariableCode.TALENTNAME:
+				case VariableCode.EXPNAME:
+				case VariableCode.MARKNAME:
+				case VariableCode.PALAMNAME:
+				case VariableCode.TRAINNAME:
+				case VariableCode.BASENAME:
+				case VariableCode.SOURCENAME:
+				case VariableCode.EXNAME:
+				case VariableCode.EQUIPNAME:
+				case VariableCode.TEQUIPNAME:
+				case VariableCode.FLAGNAME:
+				case VariableCode.TFLAGNAME:
+				case VariableCode.CFLAGNAME:
+				case VariableCode.TCVARNAME:
+				case VariableCode.CSTRNAME:
+				case VariableCode.STAINNAME:
+				case VariableCode.CDFLAGNAME1:
+				case VariableCode.CDFLAGNAME2:
+				case VariableCode.TSTRNAME:
+				case VariableCode.SAVESTRNAME:
+				case VariableCode.STRNAME:
+				case VariableCode.GLOBALNAME:
+				case VariableCode.GLOBALSNAME:
+					MaxDataList[(int)(id.Code & VariableCode.__LOWERCASE__)] = length;
+					break;
+				default:
+					{
+						if (id.IsCharacterData)
+						{
+							if (id.IsArray2D)
+							{
+								Int64 length64 = (((Int64)length) << 32) + length2;
+								if (id.IsInteger)
+									CharacterIntArray2DLength[id.CodeInt] = length64;
+								else if (id.IsString)
+									CharacterStrArray2DLength[id.CodeInt] = length64;
+							}
+							else
+							{
+								if (id.IsInteger)
+									CharacterIntArrayLength[id.CodeInt] = length;
+								else if (id.IsString)
+									CharacterStrArrayLength[id.CodeInt] = length;
+							}
+						}
+						else if (id.IsArray2D)
+						{
+							Int64 length64 = (((Int64)length) << 32) + length2;
+							if (id.IsInteger)
+								VariableIntArray2DLength[id.CodeInt] = length64;
+							else if (id.IsString)
+								VariableStrArray2DLength[id.CodeInt] = length64;
+						}
+						else if (id.IsArray3D)
+						{
+							//Int64 length3d = ((Int64)length << 32) + ((Int64)length2 << 16) + (Int64)length3;
+							Int64 length3d = ((Int64)length << 40) + ((Int64)length2 << 20) + length3;
+							if (id.IsInteger)
+								VariableIntArray3DLength[id.CodeInt] = length3d;
+							else
+								VariableStrArray3DLength[id.CodeInt] = length3d;
+						}
+						else
+						{
+							if (id.IsInteger)
+								VariableIntArrayLength[id.CodeInt] = length;
+							else if (id.IsString)
+								VariableStrArrayLength[id.CodeInt] = length;
+						}
+					}
+					break;
+			}
+			//1803beta004 二重定義を警告対象に
+			if (changedCode.Contains(id.Code))
+				ParserMediator.Warn(id.Code + "の要素数は既に定義されています(上書きします)", position, 1);
+			else
+				changedCode.Add(id.Code);
+		}
+
+		private void _decideActualArraySize_sub(VariableCode mainCode, VariableCode nameCode, int[] arraylength, ScriptPosition position)
+		{
+			int nameIndex = (int)(nameCode & VariableCode.__LOWERCASE__);
+			int mainLengthIndex = (int)(mainCode & VariableCode.__LOWERCASE__);
+			if (changedCode.Contains(nameCode) && changedCode.Contains(mainCode))
+			{
+				if (MaxDataList[nameIndex] != arraylength[mainLengthIndex])
+				{
+					int i = Math.Max(MaxDataList[nameIndex], arraylength[mainLengthIndex]);
+					arraylength[mainLengthIndex] = i;
+					MaxDataList[nameIndex] = i;
+					//1803beta004 不適切な指定として警告Lv1の対象にする
+					if (MaxDataList[nameIndex] == 0 || arraylength[mainLengthIndex] == 0)
+						ParserMediator.Warn(mainCode +"と" + nameCode + "の禁止設定が異なります(使用禁止を解除します)", position, 1);
+					else
+						ParserMediator.Warn(mainCode +"と" + nameCode + "の要素数が異なります(大きい方に合わせます)", position, 1);
+				}
+			}
+			else if (changedCode.Contains(nameCode) && !changedCode.Contains(mainCode))
+				arraylength[mainLengthIndex] = MaxDataList[nameIndex];
+			else if (!changedCode.Contains(nameCode) && changedCode.Contains(mainCode))
+				MaxDataList[nameIndex] = arraylength[mainLengthIndex];
+		}
+		
+		private void decideActualArraySize(ScriptPosition position)
+		{
+			_decideActualArraySize_sub(VariableCode.ABL, VariableCode.ABLNAME, CharacterIntArrayLength, position);
+			_decideActualArraySize_sub(VariableCode.TALENT, VariableCode.TALENTNAME, CharacterIntArrayLength, position);
+			_decideActualArraySize_sub(VariableCode.EXP, VariableCode.EXPNAME, CharacterIntArrayLength, position);
+			_decideActualArraySize_sub(VariableCode.MARK, VariableCode.MARKNAME, CharacterIntArrayLength, position);
+			_decideActualArraySize_sub(VariableCode.BASE, VariableCode.BASENAME, CharacterIntArrayLength, position);
+            _decideActualArraySize_sub(VariableCode.SOURCE, VariableCode.SOURCENAME, CharacterIntArrayLength, position);
+			_decideActualArraySize_sub(VariableCode.EX, VariableCode.EXNAME, CharacterIntArrayLength, position);
+			_decideActualArraySize_sub(VariableCode.EQUIP, VariableCode.EQUIPNAME, CharacterIntArrayLength, position);
+			_decideActualArraySize_sub(VariableCode.TEQUIP, VariableCode.TEQUIPNAME, CharacterIntArrayLength, position);
+			_decideActualArraySize_sub(VariableCode.FLAG, VariableCode.FLAGNAME, VariableIntArrayLength, position);
+			_decideActualArraySize_sub(VariableCode.TFLAG, VariableCode.TFLAGNAME, VariableIntArrayLength, position);
+			_decideActualArraySize_sub(VariableCode.CFLAG, VariableCode.CFLAGNAME, CharacterIntArrayLength, position);
+			_decideActualArraySize_sub(VariableCode.TCVAR, VariableCode.TCVARNAME, CharacterIntArrayLength, position);
+			_decideActualArraySize_sub(VariableCode.CSTR, VariableCode.CSTRNAME, CharacterStrArrayLength, position);
+			_decideActualArraySize_sub(VariableCode.STAIN, VariableCode.STAINNAME, CharacterIntArrayLength, position);
+			_decideActualArraySize_sub(VariableCode.STR, VariableCode.STRNAME, VariableStrArrayLength, position);
+			_decideActualArraySize_sub(VariableCode.TSTR, VariableCode.TSTRNAME, VariableStrArrayLength, position);
+			_decideActualArraySize_sub(VariableCode.SAVESTR, VariableCode.SAVESTRNAME, VariableStrArrayLength, position);
+			_decideActualArraySize_sub(VariableCode.GLOBAL, VariableCode.GLOBALNAME, VariableIntArrayLength, position);
+			_decideActualArraySize_sub(VariableCode.GLOBALS, VariableCode.GLOBALSNAME, VariableStrArrayLength, position);
+
+
+			//PALAM(JUEL込み)
+			//PALAMNAMEが変わっていてかつPALAMかJUELが変わっているとき、
+			if ((changedCode.Contains(VariableCode.PALAMNAME)) && (changedCode.Contains(VariableCode.PALAM) || changedCode.Contains(VariableCode.JUEL)))
+			{
+				int palamJuelMax = Math.Max(CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.PALAM)]
+						, CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.JUEL)]);
+			
+			}
+			//PALAMかJUELが変わっていれば、そのうち大きい方にPALAMNAMEをあわせる
+			if (changedCode.Contains(VariableCode.PALAM) || changedCode.Contains(VariableCode.JUEL))
+			{
+				int palamJuelMax = Math.Max(CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.PALAM)]
+						, CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.JUEL)]);
+				//PALAMNAMEが変わっている
+				if(changedCode.Contains(VariableCode.PALAMNAME))
+				{
+					if (MaxDataList[paramIndex] != palamJuelMax)
+					{
+						int i = Math.Max(MaxDataList[paramIndex], palamJuelMax);
+						MaxDataList[paramIndex] = i;
+						if(CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.PALAM)] == palamJuelMax)
+							CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.PALAM)] = i;
+						if(CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.JUEL)] == palamJuelMax)
+							CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.JUEL)] = i;
+						//1803beta004 不適切な指定として警告Lv1の対象にする
+						ParserMediator.Warn("PALAMとJUELとPALAMNAMEの要素数が不適切です", position, 1);
+					}
+				}
+				else//PALAMNAMEの指定がないなら大きい方にPALAMNAMEをあわせる
+					MaxDataList[paramIndex] = palamJuelMax;
+			}
+			//PALAMとJUEL不変でPALAMNAMEが変わっている場合
+			else if (changedCode.Contains(VariableCode.PALAMNAME))
+			{
+				//PALAMを指定のPALAMNAMEにあわせる
+				CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.PALAM)] = MaxDataList[paramIndex];
+				//指定のPALAMNAMEがJUELより小さければ警告出してJUELにあわせる
+				if (MaxDataList[paramIndex] < CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.JUEL)])
+				{
+					ParserMediator.Warn("PALAMNAMEの要素数がJUELより少なくなっています(JUELに合わせます)", position, 1);
+					MaxDataList[paramIndex] = CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.JUEL)];
+				}
+			}
+			//CDFLAG
+			//一部変更されたら双方変更されたと扱う
+			bool cdflagNameLengthChanged = changedCode.Contains(VariableCode.CDFLAGNAME1) || changedCode.Contains(VariableCode.CDFLAGNAME2);
+			int mainLengthIndex = (int)(VariableCode.__LOWERCASE__ & VariableCode.CDFLAG);
+			Int64 length64 = CharacterIntArray2DLength[mainLengthIndex];
+			int length1 = (int)(length64 >> 32);
+			int length2 = (int)(length64 & 0x7FFFFFFF);
+			if (changedCode.Contains(VariableCode.CDFLAG) && cdflagNameLengthChanged)
+			{
+				//調整が面倒なので投げる
+				if ((length1 != MaxDataList[cdflag1Index]) || (length2 != MaxDataList[cdflag2Index]))
+					throw new CodeEE("The number of elements of CDFLAG does not match the number of elements of CDFLAGNAME 1 and CDFLAGNAME 2", position);
+			}
+			else if (cdflagNameLengthChanged && !changedCode.Contains(VariableCode.CDFLAG))
+			{
+				length1 = MaxDataList[cdflag1Index];
+				length2 = MaxDataList[cdflag2Index];
+				if (length1 * length2 > 1000000)
+				{
+					//調整が面倒なので投げる
+					throw new CodeEE("CDFLAG has too many elements (product of CDFLAGNAME 1 and CDFLAGNAME 2 number of elements exceeds 1 million)", position);
+				}
+				CharacterIntArray2DLength[mainLengthIndex] = (((Int64)length1) << 32) + length2;
+			}
+			else if (!cdflagNameLengthChanged && changedCode.Contains(VariableCode.CDFLAG))
+			{
+				MaxDataList[cdflag1Index] = length1;
+				MaxDataList[cdflag2Index] = length2;
+			}
+			//もう使わないのでデータ破棄
+			changedCode.Clear();
+		}
+
+
+		public void LoadData(string csvDir, IConsole console, bool disp)
+		{
+			
+			output = console;
+			
+	
+			
+			loadVariableSizeData(csvDir + "VariableSize.CSV", disp);
+			for(int i = 0; i< countNameCsv;i++)
+			{
+				names[i] = new string[MaxDataList[i]];
+				nameToIntDics[i] = new Dictionary<string, int>();
+			}
+            // JVN: Check if file exist, keep result in canLoadParam
+            canLoadParam = File.Exists(csvDir + "PARAM.CSV");
+
+			tranls = new Translation(csvDir, ref output, canLoadParam);
+            ItemPrice = new Int64[MaxDataList[itemIndex]];
+			loadDataTo(csvDir + "ABL.CSV", ablIndex, null, disp);
+			loadDataTo(csvDir + "EXP.CSV", expIndex, null, disp);
+			loadDataTo(csvDir + "TALENT.CSV", talentIndex, null, disp);
+			loadDataTo(csvDir + (canLoadParam ? "PARAM.CSV" : "PALAM.CSV"), paramIndex, null, disp); // JVN: Change file name depending on boolean
+			loadDataTo(csvDir + "TRAIN.CSV", trainIndex, null, disp);
+			loadDataTo(csvDir + "MARK.CSV", markIndex, null, disp);
+			loadDataTo(csvDir + "ITEM.CSV", itemIndex, ItemPrice, disp);
+			loadDataTo(csvDir + "BASE.CSV", baseIndex, null, disp);
+			loadDataTo(csvDir + "SOURCE.CSV", sourceIndex, null, disp);
+			loadDataTo(csvDir + "EX.CSV", exIndex, null, disp);
+			loadDataTo(csvDir + "STR.CSV", strIndex, null, disp);
+			loadDataTo(csvDir + "EQUIP.CSV", equipIndex, null, disp);
+			loadDataTo(csvDir + "TEQUIP.CSV", tequipIndex, null, disp);
+			loadDataTo(csvDir + "FLAG.CSV", flagIndex, null, disp);
+			loadDataTo(csvDir + "TFLAG.CSV", tflagIndex, null, disp);
+			loadDataTo(csvDir + "CFLAG.CSV", cflagIndex, null, disp);
+			loadDataTo(csvDir + "TCVAR.CSV", tcvarIndex, null, disp);
+			loadDataTo(csvDir + "CSTR.CSV", cstrIndex, null, disp);
+			loadDataTo(csvDir + "STAIN.CSV", stainIndex, null, disp);
+			loadDataTo(csvDir + "CDFLAG1.CSV", cdflag1Index, null, disp);
+			loadDataTo(csvDir + "CDFLAG2.CSV", cdflag2Index, null, disp);
+			
+			loadDataTo(csvDir + "STRNAME.CSV", strnameIndex, null, disp);
+			loadDataTo(csvDir + "TSTR.CSV", tstrnameIndex, null, disp);
+			loadDataTo(csvDir + "SAVESTR.CSV", savestrnameIndex, null, disp);
+			loadDataTo(csvDir + "GLOBAL.CSV", globalIndex, null, disp);
+			loadDataTo(csvDir + "GLOBALS.CSV", globalsIndex, null, disp);
+			//逆引き辞書を作成
+			for (int i = 0; i < names.Length; i++)
+			{
+				if (i == 10)//Strは逆引き無用
+					continue;
+				string[] nameArray = names[i];
+				for (int j = 0; j < nameArray.Length; j++)
+				{
+					if (!string.IsNullOrEmpty(nameArray[j]) && !nameToIntDics[i].ContainsKey(nameArray[j]))
+						nameToIntDics[i].Add(nameArray[j], j);
+				}
+			}
+			//if (!Program.AnalysisMode)
+			loadCharacterData(csvDir, disp);
+
+			//逆引き辞書を作成2 (RELATION)
+			for (int i = 0; i < CharacterTmplList.Count; i++)
+			{
+				CharacterTemplate tmpl = CharacterTmplList[i];
+				if (!string.IsNullOrEmpty(tmpl.Name) && !relationDic.ContainsKey(tmpl.Name))
+					relationDic.Add(tmpl.Name, (int)tmpl.No);
+				if (!string.IsNullOrEmpty(tmpl.Callname) && !relationDic.ContainsKey(tmpl.Callname))
+                    relationDic.Add(tmpl.Callname, (int)tmpl.No);
+				if (!string.IsNullOrEmpty(tmpl.Nickname) && !relationDic.ContainsKey(tmpl.Nickname))
+                    relationDic.Add(tmpl.Nickname, (int)tmpl.No);
+			}
+		}
+
+		public bool isDefined(VariableCode varCode, string str)
+		{
+			if (string.IsNullOrEmpty(str))
+				return false;
+			string errPos = null;
+			Dictionary<string, int> dic = null;
+			if (varCode == VariableCode.CDFLAG)
+			{
+				dic = GetKeywordDictionary(out errPos, VariableCode.CDFLAGNAME1, -1);
+				if ((dic == null)||(!dic.ContainsKey(str)))
+					dic = GetKeywordDictionary(out errPos, VariableCode.CDFLAGNAME2, -1);
+				if (dic == null)
+					return false;
+				return dic.ContainsKey(str);
+			}
+			dic = GetKeywordDictionary(out errPos, varCode, -1);
+			if (dic == null)
+				return false;
+			return dic.ContainsKey(str);
+		}
+
+        
+		public bool TryKeywordToInteger(out int ret, VariableCode code, string key, int index)
+        {
+            ret = 0;
+            if (string.IsNullOrEmpty(key))
+                return false;
+            Dictionary<string, int> dic = null;
+            try
+            {
+                dic = GetKeywordDictionary(out _, code, index);
+				if (dic == null)
+					return false;
+            }
+            catch { return false; }
+            return (dic.TryGetValue(key, out ret));
+        }
+
+		public int KeywordToInteger(VariableCode code, string key, int index)
+		{
+			if (string.IsNullOrEmpty(key))
+				throw new CodeEE("Keywords cannot be empty");
+		    var dic = GetKeywordDictionary(out var errPos, code, index);
+			if (dic.TryGetValue(key, out var ret))
+				return ret;
+			if (errPos == null)
+				throw new CodeEE("Array variable" + code + "elements can not be specified as a string");
+			throw new CodeEE("There is no definition of\"" + key + "\" at " + errPos);
+		}
+
+		public Dictionary<string, int> GetKeywordDictionary(out string errPos, VariableCode code, int index)
+		{
+			errPos = null;
+			int allowIndex = -1;
+			Dictionary<string, int> ret = null;
+			switch (code)
+			{
+				case VariableCode.ABL:
+					ret = nameToIntDics[ablIndex];//AblName;
+					errPos = "abl.csv";
+					allowIndex = 1;
+					break;
+				case VariableCode.EXP:
+					ret = nameToIntDics[expIndex];//ExpName;
+					errPos = "exp.csv";
+					allowIndex = 1;
+					break;
+				case VariableCode.TALENT:
+					ret = nameToIntDics[talentIndex];//TalentName;
+					errPos = "talent.csv";
+					allowIndex = 1;
+					break;
+				case VariableCode.UP:
+				case VariableCode.DOWN:
+					ret = nameToIntDics[paramIndex];//ParamName 1;
+					errPos = (canLoadParam ? "param.csv" : "palam.csv"); // JVN: For error output & debugging
+                    allowIndex = 0;
+					break;
+				case VariableCode.PALAM:
+				case VariableCode.JUEL:
+				case VariableCode.GOTJUEL:
+				case VariableCode.CUP:
+				case VariableCode.CDOWN:
+					ret = nameToIntDics[paramIndex];//ParamName 2;
+					errPos = (canLoadParam ? "param.csv" : "palam.csv"); // JVN: For error output & debugging
+                    allowIndex = 1;
+					break;
+
+				case VariableCode.TRAINNAME:
+					ret = nameToIntDics[trainIndex];//TrainName;
+					errPos = "train.csv";
+					allowIndex = 0;
+					break;
+				case VariableCode.MARK:
+					ret = nameToIntDics[markIndex];//MarkName;
+					errPos = "mark.csv";
+					allowIndex = 1;
+					break;
+				case VariableCode.ITEM:
+				case VariableCode.ITEMSALES:
+				case VariableCode.ITEMPRICE:
+					ret = nameToIntDics[itemIndex];//ItemName;
+					errPos = "Item.csv";
+					allowIndex = 0;
+					break;
+				case VariableCode.LOSEBASE:
+					ret = nameToIntDics[baseIndex];//BaseName;
+					errPos = "base.csv";
+					allowIndex = 0;
+					break;
+				case VariableCode.BASE:
+				case VariableCode.MAXBASE:
+				case VariableCode.DOWNBASE:
+					ret = nameToIntDics[baseIndex];//BaseName;
+					errPos = "base.csv";
+					allowIndex = 1;
+					break;
+				case VariableCode.SOURCE:
+					ret = nameToIntDics[sourceIndex];//SourceName;
+					errPos = "source.csv";
+					allowIndex = 1;
+					break;
+				case VariableCode.EX:
+				case VariableCode.NOWEX:
+					ret = nameToIntDics[exIndex];//ExName;
+					errPos = "ex.csv";
+					allowIndex = 1;
+					break;
+
+
+				case VariableCode.EQUIP:
+					ret = nameToIntDics[equipIndex];//EquipName;
+					errPos = "equip.csv";
+					allowIndex = 1;
+					break;
+				case VariableCode.TEQUIP:
+					ret = nameToIntDics[tequipIndex];//TequipName;
+					errPos = "tequip.csv";
+					allowIndex = 1;
+					break;
+				case VariableCode.FLAG:
+					ret = nameToIntDics[flagIndex];//FlagName;
+					errPos = "flag.csv";
+					allowIndex = 0;
+					break;
+				case VariableCode.TFLAG:
+					ret = nameToIntDics[tflagIndex];//TFlagName;
+					errPos = "tflag.csv";
+					allowIndex = 0;
+					break;
+				case VariableCode.CFLAG:
+					ret = nameToIntDics[cflagIndex];//CFlagName;
+					errPos = "cflag.csv";
+					allowIndex = 1;
+					break;
+				case VariableCode.TCVAR:
+					ret = nameToIntDics[tcvarIndex];//TCVarName;
+					errPos = "tcvar.csv";
+					allowIndex = 1;
+					break;
+				case VariableCode.CSTR:
+					ret = nameToIntDics[cstrIndex];//CStrName;
+					errPos = "cstr.csv";
+					allowIndex = 1;
+					break;
+
+				case VariableCode.STAIN:
+					ret = nameToIntDics[stainIndex];//StainName;
+					errPos = "stain.csv";
+					allowIndex = 1;
+					break;
+				case VariableCode.CDFLAGNAME1:
+					ret = nameToIntDics[cdflag1Index];
+					errPos = "cdflag1.csv";
+					allowIndex = 0;
+					break;
+				case VariableCode.CDFLAGNAME2:
+					ret = nameToIntDics[cdflag2Index];
+					errPos = "cdflag2.csv";
+					allowIndex = 0;
+					break;
+				case VariableCode.CDFLAG:
+				{
+					if (index == 1)
+					{
+						ret = nameToIntDics[cdflag1Index];//CDFlagName1
+						errPos = "cdflag1.csv";
+					}
+					else if (index == 2)
+					{
+						ret = nameToIntDics[cdflag2Index];//CDFlagName2
+						errPos = "cdflag2.csv";
+					}
+					else if (index >= 0)
+						throw new CodeEE("配列変数" + code + "の" + (index + 1) + "番目の要素を文字列で指定することはできません");
+					else
+						throw new CodeEE("CDFLAGの要素の取得にはCDFLAGNAME1又はCDFLAGNAME2を使用します");
+					return ret;
+				}
+				case VariableCode.STR:
+					ret = nameToIntDics[strnameIndex];
+					errPos = "strname.csv";
+					allowIndex = 0;
+					break;
+				case VariableCode.TSTR:
+					ret = nameToIntDics[tstrnameIndex];
+					errPos = "tstr.csv";
+					allowIndex = 0;
+					break;
+				case VariableCode.SAVESTR:
+					ret = nameToIntDics[savestrnameIndex];
+					errPos = "savestr.csv";
+					allowIndex = 0;
+					break;
+				case VariableCode.GLOBAL:
+					ret = nameToIntDics[globalIndex];
+					errPos = "global.csv";
+					allowIndex = 0;
+					break;
+				case VariableCode.GLOBALS:
+					ret = nameToIntDics[globalsIndex];
+					errPos = "globals.csv";
+					allowIndex = 0;
+					break;
+				case VariableCode.RELATION:
+					ret = relationDic;
+					errPos = "chara*.csv";
+					allowIndex = 1;
+					break;
+				case VariableCode.NAME:
+					ret = relationDic;
+					errPos = "chara*.csv";
+					allowIndex = -1;
+					break;
+
+			}
+			if (index < 0)
+				return ret;
+			if (ret == null)
+				throw new CodeEE("配列変数" + code + "の要素を文字列で指定することはできません");
+			if ((index != allowIndex))
+			{
+				if (allowIndex < 0)//GETNUM専用
+					throw new CodeEE("配列変数" + code + "の要素を文字列で指定することはできません");
+				throw new CodeEE("配列変数" + code + "の" + (index + 1) + "番目の要素を文字列で指定することはできません");
+			}
+			return ret;
+		}
+
+		public CharacterTemplate GetCharacterTemplate(Int64 index)
+		{
+			foreach (CharacterTemplate chara in CharacterTmplList)
+			{
+				if (chara.No == index)
+					return chara;
+			}
+			return null;
+		}
+		
+		public CharacterTemplate GetCharacterTemplate_UseSp(Int64 index, bool sp)
+		{
+			foreach (CharacterTemplate chara in CharacterTmplList)
+			{
+				if (chara.No != index)
+					continue;
+				if (Config.CompatiSPChara && sp != chara.IsSpchara)
+					continue;
+				return chara;
+			}
+			return null;
+		}
+
+		public CharacterTemplate GetCharacterTemplateFromCsvNo(Int64 index)
+		{
+			foreach (CharacterTemplate chara in CharacterTmplList)
+			{
+				if (chara.csvNo != index)
+					continue;
+				return chara;
+			}
+			return null;
+		}
+
+		public CharacterTemplate GetPseudoChara()
+		{
+			return new CharacterTemplate(0, this);
+		}
+
+		//private CharacterData dummyChara = null;
+		//public CharacterData DummyChara
+		//{
+		//    get { if (dummyChara == null) dummyChara = new CharacterData(GlobalStatic.VEvaluator.Constant, GetPseudoChara(),varData); return dummyChara; }
+		//    set { dummyChara = value; }
+		//}
+
+		private void loadCharacterData(string csvDir, bool disp)
+		{
+			if (!Directory.Exists(csvDir))
+				return;
+			List<KeyValuePair<string, string>> csvPaths = Config.GetFiles(csvDir, "CHARA*.CSV");
+			for (int i = 0; i < csvPaths.Count; i++)
+				loadCharacterDataFile(csvPaths[i].Value, csvPaths[i].Key, disp);
+			if (useCompatiName)
+			{
+				foreach (CharacterTemplate tmpl in CharacterTmplList)
+					if (string.IsNullOrEmpty(tmpl.Callname))
+						tmpl.Callname = tmpl.Name;
+			}
+			foreach (CharacterTemplate tmpl in CharacterTmplList)
+				tmpl.SetSpFlag();
+			Dictionary<Int64, CharacterTemplate> nList = new Dictionary<Int64, CharacterTemplate>();
+			Dictionary<Int64, CharacterTemplate> spList = new Dictionary<Int64, CharacterTemplate>();
+			foreach (CharacterTemplate tmpl in CharacterTmplList)
+			{
+				Dictionary<Int64, CharacterTemplate>  targetList = nList;
+				if(Config.CompatiSPChara && tmpl.IsSpchara)
+				{
+					targetList = spList;
+				}
+				if (targetList.ContainsKey(tmpl.No))
+				{
+
+					if (!Config.CompatiSPChara && (tmpl.IsSpchara!= targetList[tmpl.No].IsSpchara))
+						ParserMediator.Warn("Character number " + tmpl.No + " was defined more than once\n" + "(To define it as an SP character please turn on compatibility option ”Allow SP characters”)", null, 1);
+					else
+						ParserMediator.Warn("Character number " + tmpl.No + " was defined more than once", null, 1);
+				}
+				else
+					targetList.Add(tmpl.No, tmpl);
+			}
+		}
+
+		private void loadCharacterDataFile(string csvPath, string csvName, bool disp)
+		{
+			CharacterTemplate tmpl = null;
+			EraStreamReader eReader = new EraStreamReader(false);
+			if (!eReader.Open(csvPath, csvName))
+			{
+				output.PrintError("Failed to open " + eReader.Filename);
+				return;
+			}
+			ScriptPosition position = null;
+			if (disp)
+				output.PrintSystemLine("Loading " + eReader.Filename + "...");
+			try
+			{
+				Int64 index = -1;
+				StringStream st = null;
+				while ((st = eReader.ReadEnabledLine()) != null)
+				{
+					position = new ScriptPosition(eReader.Filename, eReader.LineNo, st.RowString);
+					string[] tokens = st.Substring().Split(',');
+					if (tokens.Length < 2)
+					{
+						ParserMediator.Warn("\",\" is required", position, 1);
+						continue;
+					}
+					if (tokens[0].Length == 0)
+					{
+						ParserMediator.Warn("\",\"で始まっています", position, 1);
+						continue;
+					}
+					if ((tokens[0].Equals("NO", Config.SCVariable))
+						|| (tokens[0].Equals("番号", Config.SCVariable)))
+					{
+						if (tmpl != null)
+						{
+							ParserMediator.Warn("番号が二重に定義されました", position, 1);
+							continue;
+						}
+						if (!Int64.TryParse(tokens[1].TrimEnd(), out index))
+						{
+							ParserMediator.Warn(tokens[1] + "を整数値に変換できません", position, 1);
+							continue;
+						}
+						tmpl = new CharacterTemplate(index, this);
+						string no = eReader.Filename.ToUpper();
+						no = no.Substring(no.IndexOf("CHARA") + 5);
+						StringBuilder sb = new StringBuilder();
+						StringStream ss = new StringStream(no);
+						while (!ss.EOS && char.IsDigit(ss.Current))
+						{
+							sb.Append(ss.Current);
+							ss.ShiftNext();
+						}
+						if (sb.Length > 0)
+							tmpl.csvNo = Convert.ToInt64(sb.ToString());
+						else
+							tmpl.csvNo = 0;
+							//tmpl.csvNo = index;
+						CharacterTmplList.Add(tmpl);
+						continue;
+					}
+					if (tmpl == null)
+					{
+						ParserMediator.Warn("番号が定義される前に他のデータが始まりました", position, 1);
+						continue;
+					}
+					toCharacterTemplate(gamebase, position, tmpl, tokens);
+				}
+			}
+			catch
+			{
+                ShowParserError("An unexpected error has occurred", position, 3);
+			}
+			finally
+			{
+				eReader.Dispose();
+			}
+		}
+
+        private void ShowParserError(string errDescription, ScriptPosition position = null, int level = 3)
+        {
+            SystemSounds.Hand.Play();
+            if (position != null)
+                ParserMediator.Warn(errDescription, position, level);
+            else
+                output.PrintError(errDescription);
+        }
+
+		private bool tryToInt64(string str, out Int64 p)
+		{
+			p = -1;
+			if (string.IsNullOrEmpty(str))
+				return false;
+			StringStream st = new StringStream(str);
+			int sign = 1;
+			if (st.Current == '+')
+				st.ShiftNext();
+			else if (st.Current == '-')
+			{
+				sign = -1;
+				st.ShiftNext();
+			}
+			//1803beta005 char.IsDigitは全角数字とかまでひろってしまうので・・・
+			//if (!char.IsDigit(st.Current))
+			// return false;
+			switch (st.Current)
+			{
+				case '0':
+				case '1':
+				case '2':
+				case '3':
+				case '4':
+				case '5':
+				case '6':
+				case '7':
+				case '8':
+				case '9':
+					break;
+				default:
+					return false;
+			}
+			try
+			{
+				p = LexicalAnalyzer.ReadInt64(st, false);
+				p = p * sign;
+			}
+			catch
+			{
+				return false;
+			}
+			return true;
+		}
+
+		private void toCharacterTemplate(GameBase gamebase, ScriptPosition position, CharacterTemplate chara, string[] tokens)
+		{
+			if (chara == null)
+				return;
+			int length = -1;
+			Int64 p1 = -1;
+			Int64 p2 = -1;
+			Dictionary<int, Int64> intArray = null;
+			Dictionary<int, string> strArray = null;
+			Dictionary<string, int> namearray = null;
+
+			string errPos = null;
+			string varname = tokens[0].ToUpper();
+			switch (varname)
+			{
+				case "NAME":
+				case "名前":
+					chara.Name = Translation.translateChara(chara.No, Translation.CharaData.Name, tokens[1]); // JVN: This will translate the name of the character
+                    return;
+				case "CALLNAME":
+				case "呼び名":
+					chara.Callname = Translation.translateChara(chara.No, Translation.CharaData.Callname, tokens[1]); // JVN: Translate Callname
+                    return;
+				case "NICKNAME":
+				case "あだ名":
+					chara.Nickname = Translation.translateChara(chara.No, Translation.CharaData.Nickname, tokens[1]); // JVN: Translate Nickname
+					return;
+				case "MASTERNAME":
+				case "主人の呼び方":
+					chara.Mastername = Translation.translateChara(chara.No, Translation.CharaData.Mastername, tokens[1]); // JNV: Translate Mastername
+					return;
+				case "MARK":
+				case "刻印":
+					length = CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.MARK)];
+					intArray = chara.Mark;
+					namearray = nameToIntDics[markIndex];
+					errPos = "mark.csv";
+					break;
+				case "EXP":
+				case "経験":
+					length = CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.EXP)];
+					intArray = chara.Exp;
+					namearray = nameToIntDics[expIndex];//ExpName;
+					errPos = "exp.csv";
+					break;
+				case "ABL":
+				case "能力":
+					length = CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.ABL)];
+					intArray = chara.Abl;
+					namearray = nameToIntDics[ablIndex];//AblName;
+					errPos = "abl.csv";
+					break;
+				case "BASE":
+				case "基礎":
+					length = CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.MAXBASE)];
+					intArray = chara.Maxbase;
+					namearray = nameToIntDics[baseIndex];//BaseName;
+					errPos = "base.csv";
+					break;
+				case "TALENT":
+				case "素質":
+					length = CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.TALENT)];
+					intArray = chara.Talent;
+					namearray = nameToIntDics[talentIndex];//TalentName;
+					errPos = "talent.csv";
+					break;
+				case "RELATION":
+				case "相性":
+					length = CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.RELATION)];
+					intArray = chara.Relation;
+					namearray = null;
+					break;
+				case "CFLAG":
+				case "フラグ":
+					length = CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.CFLAG)];
+					intArray = chara.CFlag;
+					namearray = nameToIntDics[cflagIndex];//CFlagName;
+					errPos = "cflag.csv";
+					break;
+				case "EQUIP":
+				case "装着物":
+					length = CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.EQUIP)];
+					intArray = chara.Equip;
+					namearray = nameToIntDics[equipIndex];//EquipName;
+					errPos = "equip.csv";
+					break;
+				case "JUEL":
+				case "珠":
+					length = CharacterIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.JUEL)];
+					intArray = chara.Juel;
+					namearray = nameToIntDics[paramIndex];//ParamName;
+					errPos = (canLoadParam ? "param.csv" : "palam.csv"); // JVN: For error output & debugging
+                    break;
+				case "CSTR":
+					length = CharacterStrArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.CSTR)];
+					strArray = chara.CStr;
+					namearray = nameToIntDics[cstrIndex];//CStrName;
+					errPos = "cstr.csv";
+					break;
+				default:
+					ParserMediator.Warn("\"" + tokens[0] + "\" cannot be interpreted", position, 1);
+					return;
+			}
+			if (length < 0)
+			{
+				ParserMediator.Warn("Program error", position, 3);
+				return;
+			}
+			if (length == 0)
+			{
+				ParserMediator.Warn(varname + " is a prohibited set variable", position, 2);
+				return;
+			}
+			bool p1isNumeric = tryToInt64(tokens[1].TrimEnd(), out p1);
+			if (p1isNumeric && ((p1 < 0) || (p1 >= length)))
+			{
+				ParserMediator.Warn(p1 + " is out of the range of the array", position, 1);
+				return;
+			}
+			int index = (int)p1;
+			if ((!p1isNumeric) && (namearray != null))
+			{
+				if (!namearray.TryGetValue(tokens[1], out index))
+				{
+					ParserMediator.Warn(errPos + "に\"" + tokens[1] + "\"の定義がありません", position, 1);
+					//ParserMediator.Warn("\"" + tokens[1] + "\" cannot be interpreted", position, 1);
+					return;
+				}
+
+				if (index >= length)
+				{
+					ParserMediator.Warn("\"" + tokens[1] + "\"は配列の範囲外です", position, 1);
+					return;
+				}
+			}
+
+			if ((index < 0) || (index >= length))
+			{
+				if (p1isNumeric)
+					ParserMediator.Warn(index + "は配列の範囲外です", position, 1);
+				else if (tokens[1].Length == 0)
+					ParserMediator.Warn("二つ目の識別子がありません", position, 1);
+				else
+					ParserMediator.Warn("\"" + tokens[1] + "\" cannot be interpreted", position, 1);
+				return;
+			}
+			if (strArray != null)
+			{
+				if (tokens.Length < 3)
+					ParserMediator.Warn("三つ目の識別子がありません", position, 1);
+				if (strArray.ContainsKey(index))
+					ParserMediator.Warn(varname + "の" + index + "番目の要素は既に定義されています(上書きします)", position, 1);
+				strArray[index] = Translation.translateChara(chara.No, Translation.CharaData.CSTR, tokens[2], index); // JVN: Finally, this translates CSTRs
+			}
+			else
+			{
+				if ((tokens.Length < 3) || !tryToInt64(tokens[2], out p2))
+					p2 = 1;
+				if (intArray.ContainsKey(index))
+					ParserMediator.Warn(varname + "の" + index + "番目の要素は既に定義されています(上書きします)", position, 1);
+				intArray[index] = p2;
+			}
+		}
+
+
+		private void loadDataTo(string csvPath, int targetIndex, Int64[] targetI, bool disp)
+		{
+
+			if (!File.Exists(csvPath))
+				return;
+			string[] target = names[targetIndex];
+            List<int> defined = new List<int>();
+			EraStreamReader eReader = new EraStreamReader(false);
+			if (!eReader.Open(csvPath))
+			{
+				output.PrintError("Failed to open " + eReader.Filename);
+				return;
+			}
+			ScriptPosition position = null;
+
+			if (disp || Program.AnalysisMode)
+				output.PrintSystemLine("Loading " + eReader.Filename + "...");
+			try
+			{
+				StringStream st = null;
+				while ((st = eReader.ReadEnabledLine()) != null)
+				{
+					position = new ScriptPosition(eReader.Filename, eReader.LineNo, st.RowString);
+					string[] tokens = st.Substring().Split(',');
+					if (tokens.Length < 2)
+					{
+						ParserMediator.Warn("\",\" is required", position, 1);
+						continue;
+					}
+					int index = 0;
+					if (!Int32.TryParse(tokens[0], out index))
+					{
+						ParserMediator.Warn("The first value cannot be converted to an integer value", position, 1);
+						continue;
+					}
+					if (target.Length == 0)
+					{
+						ParserMediator.Warn("Prohibited set name array", position, 2);
+						break;
+					}
+					if ((index < 0) || (target.Length <= index))
+					{
+						ParserMediator.Warn(index + "は配列の範囲外です", position, 1);
+						continue;
+					}
+                    if (defined.Contains(index))
+                        ParserMediator.Warn(index + "番目の要素はすでに定義されています(新しい値で上書きします)", position, 1);
+                    else
+                        defined.Add(index);
+					target[index] = tokens[1];
+					if ((targetI != null) && (tokens.Length >= 3))
+					{
+						Int64 price;
+
+						if (!Int64.TryParse(tokens[2].TrimEnd(), out price))
+						{
+							ParserMediator.Warn("Couldn\'t read amount of money", position, 1);
+							continue;
+						}
+
+						targetI[index] = price;
+					}
+				}
+			}
+			catch
+			{
+                ShowParserError("An unexpected error has occurred", position, 3);
+            }
+			finally
+			{
+				eReader.Close();
+			}
+
+
+		}
+	}
+
+	internal sealed class CharacterTemplate
+	{
+		int[] arraySize;
+		int cstrSize;
+
+		public string Name;
+		public string Callname;
+		public string Nickname;
+		public string Mastername;
+		public readonly Int64 No;
+		public readonly Dictionary<Int32, Int64> Maxbase = new Dictionary<Int32, Int64>();
+		public readonly Dictionary<Int32, Int64> Mark = new Dictionary<Int32, Int64>();
+		public readonly Dictionary<Int32, Int64> Exp = new Dictionary<Int32, Int64>();
+		public readonly Dictionary<Int32, Int64> Abl = new Dictionary<Int32, Int64>();
+		public readonly Dictionary<Int32, Int64> Talent = new Dictionary<Int32, Int64>();
+		public readonly Dictionary<Int32, Int64> Relation = new Dictionary<Int32, Int64>();
+		public readonly Dictionary<Int32, Int64> CFlag = new Dictionary<Int32, Int64>();
+		public readonly Dictionary<Int32, Int64> Equip = new Dictionary<Int32, Int64>();
+		public readonly Dictionary<Int32, Int64> Juel = new Dictionary<Int32, Int64>();
+		public readonly Dictionary<Int32, string> CStr = new Dictionary<Int32, string>();
+		public Int64 csvNo;
+		public bool IsSpchara { get; private set; }
+		
+		public CharacterTemplate(Int64 index, ConstantData constant)
+		{
+			arraySize = constant.CharacterIntArrayLength;
+			cstrSize = constant.CharacterStrArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.CSTR)];
+			No = index;
+		}
+		public int ArrayStrLength(CharacterStrData type)
+		{
+			switch (type)
+			{
+				case CharacterStrData.CSTR:
+					return cstrSize;
+				default:
+					throw new CodeEE("Attempted to refer to a key that does not exist");
+			}
+		}
+
+		public int ArrayLength(CharacterIntData type)
+		{
+			switch (type)
+			{
+				case CharacterIntData.BASE:
+					{
+						int size = arraySize[(int)(VariableCode.__LOWERCASE__ & VariableCode.BASE)];
+						int maxSize = arraySize[(int)(VariableCode.__LOWERCASE__ & VariableCode.MAXBASE)];
+						return size > maxSize ? size : maxSize;
+					}
+				case CharacterIntData.MARK:
+					return arraySize[(int)(VariableCode.__LOWERCASE__ & VariableCode.MARK)];
+				case CharacterIntData.ABL:
+					return arraySize[(int)(VariableCode.__LOWERCASE__ & VariableCode.ABL)];
+				case CharacterIntData.EXP:
+					return arraySize[(int)(VariableCode.__LOWERCASE__ & VariableCode.EXP)];
+				case CharacterIntData.RELATION:
+					return arraySize[(int)(VariableCode.__LOWERCASE__ & VariableCode.RELATION)];
+				case CharacterIntData.TALENT:
+					return arraySize[(int)(VariableCode.__LOWERCASE__ & VariableCode.TALENT)];
+				case CharacterIntData.CFLAG:
+					return arraySize[(int)(VariableCode.__LOWERCASE__ & VariableCode.CFLAG)];
+				case CharacterIntData.EQUIP:
+					return arraySize[(int)(VariableCode.__LOWERCASE__ & VariableCode.EQUIP)];
+				case CharacterIntData.JUEL:
+					return arraySize[(int)(VariableCode.__LOWERCASE__ & VariableCode.JUEL)];
+				default:
+					throw new CodeEE("Attempted to refer to a key that does not exist");
+			}
+		}
+
+		internal void SetSpFlag()
+		{
+			if (CFlag.ContainsKey(0) && CFlag[0] != 0L)
+				IsSpchara = true;
+		}
+	}
+}

+ 26 - 0
NTERA/Game/GameData/DefineMacro.cs

@@ -0,0 +1,26 @@
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameData
+{
+	internal sealed class DefineMacro
+	{
+		public DefineMacro(string key, WordCollection wc, int argcount)
+		{
+			Keyword = key;
+			Statement = wc;
+			ArgCount = argcount;
+			Statement.Pointer = 0;
+			HasArguments = argcount != 0;
+			if (Statement.Collection.Count == 1)
+				IDWord = Statement.Current as IdentifierWord;
+			IsNull = wc.Collection.Count == 0;
+		}
+		public readonly string Keyword;
+		public readonly int ArgCount;
+		public readonly WordCollection Statement;
+		public readonly IdentifierWord IDWord;
+		public readonly bool HasArguments;
+		public readonly bool IsNull;
+
+	}
+}

+ 78 - 0
NTERA/Game/GameData/Expression/CaseExpression.cs

@@ -0,0 +1,78 @@
+using System;
+using System.Reflection;
+
+namespace MinorShift.Emuera.GameData.Expression
+{
+	//難読化用属性。enum.ToString()やenum.Parse()を行うなら(Exclude=true)にすること。
+	[Obfuscation(Exclude=false)]
+	internal enum CaseExpressionType
+	{
+		Normal = 1,
+		To = 2,
+		Is = 3
+	}
+	internal sealed class CaseExpression
+	{
+		public CaseExpressionType CaseType = CaseExpressionType.Normal;
+		public IOperandTerm LeftTerm;
+		public IOperandTerm RightTerm;
+
+		public OperatorCode Operator;
+		public Type GetOperandType()
+		{
+			if(LeftTerm != null)
+				return LeftTerm.GetOperandType();
+			return typeof(void);
+		}
+		
+		public void Reduce(ExpressionMediator exm)
+		{
+			LeftTerm = LeftTerm.Restructure(exm);
+			if (CaseType == CaseExpressionType.To)
+				RightTerm = RightTerm.Restructure(exm);
+		}
+		
+		public override string ToString()
+		{
+			switch (CaseType)
+			{
+				case CaseExpressionType.Normal:
+					return LeftTerm.ToString();
+				case CaseExpressionType.Is:
+					return "Is " + Operator + " " + LeftTerm;
+				case CaseExpressionType.To:
+					return LeftTerm + " To " + RightTerm;
+			}
+
+			return base.ToString();
+		}
+
+		public bool GetBool(Int64 Is, ExpressionMediator exm)
+		{
+			if (CaseType == CaseExpressionType.To)
+				return LeftTerm.GetIntValue(exm) <= Is && Is <= RightTerm.GetIntValue(exm);
+			if (CaseType == CaseExpressionType.Is)
+			{
+				IOperandTerm term = OperatorMethodManager.ReduceBinaryTerm(Operator, new SingleTerm(Is), LeftTerm);
+				return term.GetIntValue(exm) != 0;
+			}
+			return LeftTerm.GetIntValue(exm) == Is;
+		}
+		
+		public bool GetBool(string Is, ExpressionMediator exm)
+		{
+			if (CaseType == CaseExpressionType.To)
+			{
+				return string.Compare(LeftTerm.GetStrValue(exm), Is, Config.SCExpression) <= 0
+					&& string.Compare(Is, RightTerm.GetStrValue(exm), Config.SCExpression) <= 0;
+			}
+			if (CaseType == CaseExpressionType.Is)
+			{
+				IOperandTerm term = OperatorMethodManager.ReduceBinaryTerm(Operator, new SingleTerm(Is), LeftTerm);
+				return term.GetIntValue(exm) != 0;
+			}
+			return LeftTerm.GetStrValue(exm) == Is;
+		}
+	}
+}
+

+ 144 - 0
NTERA/Game/GameData/Expression/ExpressionMediator.cs

@@ -0,0 +1,144 @@
+using System;
+using System.Text;
+using Microsoft.VisualBasic;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.GameProc;
+using MinorShift.Emuera.GameProc.Function;
+using MinorShift.Emuera.Sub;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera.GameData.Expression
+{
+	//1756 元ExpressionEvaluator。GetValueの仕事はなくなったので改名。
+	//IOperandTerm間での通信や共通の処理に使う。
+	//変数が絡む仕事はVariableEvaluatorへ。
+	internal sealed class ExpressionMediator
+	{
+		public ExpressionMediator(Process proc, VariableEvaluator vev, IConsole console)
+		{
+			VEvaluator = vev;
+			Process = proc;
+			Console = console;
+		}
+		public readonly VariableEvaluator VEvaluator;
+		public readonly Process Process;
+		public readonly IConsole Console;
+		
+		
+		
+		private bool forceHiragana;
+		private bool forceKatakana;
+		private bool halftoFull;
+		
+		public void ForceKana(Int64 flag)
+		{
+			if (flag < 0 || flag > 3)
+				throw new CodeEE("命令FORCEKANAの引数が指定可能な範囲(0~3)を超えています");
+			forceKatakana = (flag == 1) ? true : false;
+			forceHiragana = (flag > 1) ? true : false;
+			halftoFull = (flag == 3) ? true : false;
+		}
+		
+		public bool ForceKana()
+		{
+			return (forceHiragana | forceKatakana | halftoFull);
+		}
+
+		public void OutputToConsole(string str, FunctionIdentifier func)
+		{
+			if (func.IsPrintSingle())
+				Console.PrintSingleLine(str, false);
+			else
+			{
+				Console.Print(str);
+				if (func.IsNewLine() || func.IsWaitInput())
+				{
+					Console.NewLine();
+					if (func.IsWaitInput())
+						Console.ReadAnyKey();
+				}
+			}
+			Console.UseSetColorStyle = true;
+		}
+
+		public string ConvertStringType(string str)
+		{
+			if (!(forceHiragana | forceKatakana | halftoFull))
+				return str;
+			if (forceKatakana)
+                return Strings.StrConv(str, VbStrConv.Katakana, 0x0411);
+			if (forceHiragana)
+			{
+				if (halftoFull)
+					return Strings.StrConv(str, VbStrConv.Hiragana | VbStrConv.Wide, 0x0411);
+				return Strings.StrConv(str, VbStrConv.Hiragana, 0x0411);
+			}
+			return str;
+		}
+
+		public string CheckEscape(string str)
+		{
+			StringStream st = new StringStream(str);
+			StringBuilder buffer = new StringBuilder();
+
+			while (!st.EOS)
+			{
+				//エスケープ文字の使用
+				if (st.Current == '\\')
+				{
+					st.ShiftNext();
+					switch (st.Current)
+					{
+						case '\\':
+							buffer.Append('\\');
+							buffer.Append('\\');
+							break;
+						case '{':
+						case '}':
+						case '%':
+						case '@':
+							buffer.Append('\\');
+							buffer.Append(st.Current);
+							break;
+						default:
+							buffer.Append("\\\\");
+							buffer.Append(st.Current);
+							break;
+					}
+					st.ShiftNext();
+					continue;
+				}
+				buffer.Append(st.Current);
+				st.ShiftNext();
+			}
+			return buffer.ToString();
+		}
+
+		public string CreateBar(Int64 var, Int64 max, Int64 length)
+		{
+			if (max <= 0)
+				throw new CodeEE("BARの最大値が正の値ではありません");
+			if (length <= 0)
+				throw new CodeEE("BARの長さが正の値ではありません");
+			if (length >= 100)//暴走を防ぐため。
+				throw new CodeEE("BARが長すぎます");
+			StringBuilder builder = new StringBuilder();
+			builder.Append('[');
+			int count;
+			unchecked
+			{
+				count = (int)(var * length / max);
+			}
+			if (count < 0)
+				count = 0;
+			if (count > length)
+				count = (int)length;
+			builder.Append(Config.BarChar1, count);
+			builder.Append(Config.BarChar2, (int)length - count);
+			builder.Append(']');
+			return builder.ToString();
+		}
+	}
+}
+
+

+ 623 - 0
NTERA/Game/GameData/Expression/ExpressionParser.cs

@@ -0,0 +1,623 @@
+using System;
+using System.Collections.Generic;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.Sub;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera.GameData.Expression
+{
+
+	internal enum ArgsEndWith
+	{
+		None,
+		EoL,
+		RightParenthesis,//)終端
+		RightBracket//]終端
+	}
+
+	internal enum TermEndWith
+	{
+		None = 0x0000,
+		EoL = 0x0001,
+		Comma = 0x0002,//','終端
+		RightParenthesis = 0x0004,//')'終端
+		RightBracket = 0x0008,//')'終端
+		Assignment = 0x0010,//')'終端
+
+		RightParenthesis_Comma = RightParenthesis | Comma,//',' or ')'終端
+		RightBracket_Comma = RightBracket | Comma,//',' or ']'終端
+		Comma_Assignment = Comma | Assignment,//',' or '='終端
+		RightParenthesis_Comma_Assignment = RightParenthesis | Comma | Assignment,//',' or ')' or '='終端
+		RightBracket_Comma_Assignment = RightBracket | Comma | Assignment//',' or ']' or '='終端
+	}
+
+    internal static class ExpressionParser
+	{
+		#region public Reduce
+		/// <summary>
+		/// カンマで区切られた引数を一括して取得。
+		/// return時にはendWithの次の文字がCurrentになっているはず。終端の適切さの検証はExpressionParserがが行う。
+		/// 呼び出し元はCodeEEを適切に処理すること
+		/// </summary>
+		/// <returns></returns>
+		public static IOperandTerm[] ReduceArguments(WordCollection wc, ArgsEndWith endWith, bool isDefine)
+		{
+			if(wc == null)
+				throw new ExeEE("空のストリームを渡された");
+			List<IOperandTerm> terms = new List<IOperandTerm>();
+			TermEndWith termEndWith = TermEndWith.EoL;
+			switch (endWith)
+			{
+				case ArgsEndWith.EoL:
+					termEndWith = TermEndWith.Comma;
+					break;
+                //case ArgsEndWith.RightBracket:
+                //    termEndWith = TermEndWith.RightBracket_Comma;
+                //    break;
+				case ArgsEndWith.RightParenthesis:
+					termEndWith = TermEndWith.RightParenthesis_Comma;
+					break;
+			}
+			TermEndWith termEndWith_Assignment = termEndWith | TermEndWith.Assignment;
+			while (true)
+			{
+				Word word = wc.Current;
+				switch (word.Type)
+				{
+					case '\0':
+                        if (endWith == ArgsEndWith.RightBracket)
+                            throw new CodeEE("'['に対応する']'が見つかりません");
+						if (endWith == ArgsEndWith.RightParenthesis)
+							throw new CodeEE("'('に対応する')'が見つかりません");
+						goto end;
+					case ')':
+						if (endWith == ArgsEndWith.RightParenthesis)
+						{
+							wc.ShiftNext();
+							goto end;
+						}
+						throw new CodeEE("構文解析中に予期しない')'を発見しました");
+                    case ']':
+                        if (endWith == ArgsEndWith.RightBracket)
+                        {
+                            wc.ShiftNext();
+                            goto end;
+                        }
+                        throw new CodeEE("構文解析中に予期しない']'を発見しました");
+				}
+				if(!isDefine)
+					terms.Add(ReduceExpressionTerm(wc, termEndWith));
+				else
+				{
+					terms.Add(ReduceExpressionTerm(wc, termEndWith_Assignment));
+                    if (terms[terms.Count - 1] == null)
+                        throw new CodeEE("関数定義の引数は省略できません");
+					if (wc.Current is OperatorWord)
+					{//=がある
+						wc.ShiftNext();
+						IOperandTerm term = reduceTerm(wc, false, termEndWith, VariableCode.__NULL__);
+						if (term == null)
+							throw new CodeEE("'='の後に式がありません");
+						if (term.GetOperandType() != terms[terms.Count - 1].GetOperandType())
+							throw new CodeEE("'='の前後で型が一致しません");
+						terms.Add(term);
+					}
+					else
+					{
+						if (terms[terms.Count - 1].GetOperandType() == typeof(Int64))
+							terms.Add(new NullTerm(0));
+						else
+							terms.Add(new NullTerm(""));
+					}
+				}
+				if (wc.Current.Type == ',')
+					wc.ShiftNext();
+			}
+		end:
+            IOperandTerm[] ret = new IOperandTerm[terms.Count];
+			terms.CopyTo(ret);
+			return ret;
+		}
+
+
+		/// <summary>
+		/// 数式または文字列式。CALLの引数などを扱う。nullを返すことがある。
+		/// return時にはendWithの文字がCurrentになっているはず。終端の適切さの検証は呼び出し元が行う。
+		/// </summary>
+		/// <param name="st"></param>
+		/// <returns></returns>
+        public static IOperandTerm ReduceExpressionTerm(WordCollection wc, TermEndWith endWith)
+        {
+			IOperandTerm term = reduceTerm(wc, false, endWith, VariableCode.__NULL__);
+            return term;
+        }
+
+
+		///// <summary>
+		///// 単純文字列、書式付文字列、文字列式のうち、文字列式を取り扱う。
+		///// 終端記号が正しいかどうかは呼び出し元で調べること
+		///// </summary>
+		///// <param name="st"></param>
+		///// <returns></returns>
+		//public static IOperandTerm ReduceStringTerm(WordCollection wc, TermEndWith endWith)
+		//{
+		//    IOperandTerm term = reduceTerm(wc, false, endWith, VariableCode.__NULL__);
+		//    if (term.GetOperandType() != typeof(string))
+		//        throw new CodeEE("式の結果が文字列ではありません");
+		//    return term;
+		//}
+
+		public static IOperandTerm ReduceIntegerTerm(WordCollection wc, TermEndWith endwith)
+		{
+			IOperandTerm term = reduceTerm(wc, false, endwith, VariableCode.__NULL__);
+            if (term == null)
+                throw new CodeEE("構文を式として解釈できません");
+			if (term.GetOperandType() != typeof(Int64))
+				throw new CodeEE("式の結果が数値ではありません");
+			return term;
+		}
+
+		
+        /// <summary>
+        /// 結果次第ではSingleTermを返すことがある。
+        /// </summary>
+        /// <returns></returns>
+		public static IOperandTerm ToStrFormTerm(StrFormWord sfw)
+		{
+			StrForm strf = StrForm.FromWordToken(sfw);
+			if(strf.IsConst)
+				return new SingleTerm(strf.GetString(null));
+			return new StrFormTerm(strf);
+		}
+
+		/// <summary>
+		/// カンマで区切られたCASEの引数を一括して取得。行端で終わる。
+		/// </summary>
+		/// <param name="st"></param>
+		/// <returns></returns>
+		public static CaseExpression[] ReduceCaseExpressions(WordCollection wc)
+		{
+			List<CaseExpression> terms = new List<CaseExpression>();
+			while (!wc.EOL)
+			{
+				terms.Add(reduceCaseExpression(wc));
+				wc.ShiftNext();
+			}
+			CaseExpression[] ret = new CaseExpression[terms.Count];
+			terms.CopyTo(ret);
+			return ret;
+		}
+
+		public static IOperandTerm ReduceVariableArgument(WordCollection wc, VariableCode varCode)
+		{
+			IOperandTerm ret = reduceTerm(wc, false, TermEndWith.EoL, varCode);
+			if(ret == null)
+                throw new CodeEE("変数の:の後に引数がありません");
+			return ret;
+		}
+
+		public static VariableToken ReduceVariableIdentifier(WordCollection wc, string idStr)
+		{
+			string subId = null;
+			if (wc.Current.Type == '@')
+			{
+				wc.ShiftNext();
+				IdentifierWord subidWT = wc.Current as IdentifierWord;
+				if (subidWT == null)
+					throw new CodeEE("@の使い方が不正です");
+				wc.ShiftNext();
+				subId = subidWT.Code;
+			}
+			return GlobalStatic.IdentifierDictionary.GetVariableToken(idStr, subId, true);
+		}
+
+
+		/// <summary>
+		/// 識別子一つを解決
+		/// </summary>
+		/// <param name="wc"></param>
+		/// <param name="idStr">識別子文字列</param>
+		/// <param name="varCode">変数の引数の場合はその変数のCode。連想配列的につかう</param>
+		/// <returns></returns>
+		private static IOperandTerm reduceIdentifier(WordCollection wc, string idStr, VariableCode varCode)
+		{
+			wc.ShiftNext();
+			SymbolWord symbol = wc.Current as SymbolWord;
+			if (symbol != null && symbol.Type == '.')
+			{//名前空間
+				throw new NotImplCodeEE();
+			}
+
+			if (symbol != null && (symbol.Type == '(' || symbol.Type == '['))
+			{//関数
+				wc.ShiftNext();
+				if (symbol.Type == '[')//1810 多分永久に実装されない
+					throw new CodeEE("[]を使った機能はまだ実装されていません");
+				//引数を処理
+				IOperandTerm[] args = ReduceArguments(wc, ArgsEndWith.RightParenthesis, false);
+				IOperandTerm mToken = GlobalStatic.IdentifierDictionary.GetFunctionMethod(GlobalStatic.LabelDictionary, idStr, args, false);
+				if (mToken == null)
+				{
+					if (!Program.AnalysisMode)
+						GlobalStatic.IdentifierDictionary.ThrowException(idStr, true);
+					else
+					{
+						if (GlobalStatic.tempDic.ContainsKey(idStr))
+							GlobalStatic.tempDic[idStr]++;
+						else
+							GlobalStatic.tempDic.Add(idStr, 1);
+						return new NullTerm(0);
+					}
+				}
+				return mToken;
+			}
+
+			//変数 or キーワード
+			idStr = idStr.Replace("PARAM","PALAM"); // JVN: cheatsy doodles activate! PARAM becomes PALAM internally, things now work
+			VariableToken id = ReduceVariableIdentifier(wc, idStr);
+			if (id != null)//idStrが変数名の場合、
+			{
+				if (varCode != VariableCode.__NULL__)//変数の引数が引数を持つことはない
+					return VariableParser.ReduceVariable(id, null, null, null);
+				return VariableParser.ReduceVariable(id, wc);
+			}
+			//idStrが変数名でない場合、
+			IOperandTerm refToken = GlobalStatic.IdentifierDictionary.GetFunctionMethod(GlobalStatic.LabelDictionary, idStr, null, false);
+			if (refToken != null)//関数参照と名前が一致したらそれを返す。実際に使うとエラー
+				return refToken;
+			if (varCode != VariableCode.__NULL__ && GlobalStatic.ConstantData.isDefined(varCode, idStr))//連想配列的な可能性アリ
+				return new SingleTerm(idStr);
+			GlobalStatic.IdentifierDictionary.ThrowException(idStr, false);
+			throw new ExeEE("エラー投げ損ねた");//ここまででthrowかreturnのどちらかをするはず。
+		}
+
+		#endregion
+
+		#region private reduce
+		private static CaseExpression reduceCaseExpression(WordCollection wc)
+		{
+			CaseExpression ret = new CaseExpression();
+			IdentifierWord id = wc.Current as IdentifierWord;
+			if ((id != null) && (id.Code.Equals("IS", Config.SCVariable)))
+			{
+				wc.ShiftNext();
+				ret.CaseType = CaseExpressionType.Is;
+				OperatorWord opWT = wc.Current as OperatorWord;
+				if (opWT == null)
+					throw new CodeEE("ISキーワードの後に演算子がありません");
+
+				OperatorCode op = opWT.Code;
+				if (!OperatorManager.IsBinary(op))
+					throw new CodeEE("ISキーワードの後の演算子が2項演算子ではありません");
+				wc.ShiftNext();
+				ret.Operator = op;
+				ret.LeftTerm = reduceTerm(wc, false, TermEndWith.Comma, VariableCode.__NULL__);
+				if (ret.LeftTerm == null)
+					throw new CodeEE("ISキーワードの後に式がありません");
+				Type type = ret.LeftTerm.GetOperandType();
+				return ret;
+			}
+			ret.LeftTerm = reduceTerm(wc, true, TermEndWith.Comma, VariableCode.__NULL__);
+			if (ret.LeftTerm == null)
+				throw new CodeEE("CASEの引数は省略できません");
+			id = wc.Current as IdentifierWord;
+			if ((id != null) && (id.Code.Equals("TO", Config.SCVariable)))
+			{
+				ret.CaseType = CaseExpressionType.To;
+				wc.ShiftNext();
+				ret.RightTerm = reduceTerm(wc, true, TermEndWith.Comma, VariableCode.__NULL__);
+				if (ret.RightTerm == null)
+					throw new CodeEE("TOキーワードの後に式がありません");
+				id = wc.Current as IdentifierWord;
+				if ((id != null) && (id.Code.Equals("TO", Config.SCVariable)))
+					throw new CodeEE("TOキーワードが2度使われています");
+				if (ret.LeftTerm.GetOperandType() != ret.RightTerm.GetOperandType())
+					throw new CodeEE("TOキーワードの前後の型が一致していません");
+				return ret;
+			}
+			ret.CaseType = CaseExpressionType.Normal;
+			return ret;
+		}
+
+
+		/// <summary>
+		/// 解析器の本体
+		/// </summary>
+		/// <param name="wc"></param>
+		/// <param name="allowKeywordTo">TOキーワードが見つかっても良いか</param>
+		/// <param name="endWith">終端記号</param>
+		/// <returns></returns>
+        private static IOperandTerm reduceTerm(WordCollection wc, bool allowKeywordTo, TermEndWith endWith, VariableCode varCode)
+        {
+            TermStack stack = new TermStack();
+            //int termCount = 0;
+            int ternaryCount = 0;
+            OperatorCode formerOp = OperatorCode.NULL;
+			bool varArg = varCode != VariableCode.__NULL__;
+			do
+			{
+				Word token = wc.Current;
+				switch (token.Type)
+				{
+					case '\0':
+						goto end;
+					case '"'://LiteralStringWT
+						stack.Add(((LiteralStringWord)token).Str);
+						break;
+					case '0'://LiteralIntegerWT
+						stack.Add(((LiteralIntegerWord)token).Int);
+						break;
+					case 'F'://FormattedStringWT
+						stack.Add(ToStrFormTerm((StrFormWord)token));
+						break;
+					case 'A'://IdentifierWT
+						{
+							string idStr = (((IdentifierWord)token).Code);
+							if (idStr.Equals("TO", Config.SCVariable))
+							{
+								if (allowKeywordTo)
+									goto end;
+								throw new CodeEE("TOキーワードはここでは使用できません");
+							}
+
+							if (idStr.Equals("IS", Config.SCVariable))
+								throw new CodeEE("ISキーワードはここでは使用できません");
+							stack.Add(reduceIdentifier(wc, idStr, varCode));
+							continue;
+						}
+
+					case '='://OperatorWT
+						{
+							if (varArg)
+								throw new CodeEE("変数の引数の読み取り中に予期しない演算子を発見しました");
+							OperatorCode op = ((OperatorWord)token).Code;
+							if (op == OperatorCode.Assignment)
+							{
+								if ((endWith & TermEndWith.Assignment) == TermEndWith.Assignment)
+									goto end;
+								throw new CodeEE("式中で代入演算子'='が使われています(等価比較には'=='を使用してください)");
+							}
+
+							if (formerOp == OperatorCode.Equal || formerOp == OperatorCode.Greater || formerOp == OperatorCode.Less
+								|| formerOp == OperatorCode.GreaterEqual || formerOp == OperatorCode.LessEqual || formerOp == OperatorCode.NotEqual)
+							{
+								if (op == OperatorCode.Equal || op == OperatorCode.Greater || op == OperatorCode.Less
+								|| op == OperatorCode.GreaterEqual || op == OperatorCode.LessEqual || op == OperatorCode.NotEqual)
+								{
+									ParserMediator.Warn("(構文上の注意)比較演算子が連続しています。", GlobalStatic.Process.GetScaningLine(), 0, false, false);
+								}
+							}
+							stack.Add(op);
+							formerOp = op;
+							if (op == OperatorCode.Ternary_a)
+								ternaryCount++;
+							else if (op == OperatorCode.Ternary_b)
+							{
+								if (ternaryCount > 0)
+									ternaryCount--;
+								else
+									throw new CodeEE("対応する'?'のない'#'です");
+							}
+							break;
+						}
+					case '(':
+						wc.ShiftNext();
+                        IOperandTerm inTerm = reduceTerm(wc, false, TermEndWith.RightParenthesis, VariableCode.__NULL__);
+                        if (inTerm == null)
+                            throw new CodeEE("かっこ\"(\"~\")\"の中に式が含まれていません");
+						stack.Add(inTerm);
+						if (wc.Current.Type != ')')
+							throw new CodeEE("対応する')'のない'('です");
+						//termCount++;
+						wc.ShiftNext();
+						continue;
+					case ')':
+						if ((endWith & TermEndWith.RightParenthesis) == TermEndWith.RightParenthesis)
+							goto end;
+						throw new CodeEE("構文解釈中に予期しない記号'" + token.Type + "'を発見しました");
+					case ']':
+						if ((endWith & TermEndWith.RightBracket) == TermEndWith.RightBracket)
+							goto end;
+						throw new CodeEE("構文解釈中に予期しない記号'" + token.Type + "'を発見しました");
+					case ',':
+						if ((endWith & TermEndWith.Comma) == TermEndWith.Comma)
+							goto end;
+						throw new CodeEE("構文解釈中に予期しない記号'" + token.Type + "'を発見しました");
+					case 'M':
+						throw new ExeEE("マクロ解決失敗");
+					default:
+						throw new CodeEE("構文解釈中に予期しない記号'" + token.Type + "'を発見しました");
+				}
+				//termCount++;
+				wc.ShiftNext();
+			} while (!varArg);
+		end:
+            if (ternaryCount > 0)
+                throw new CodeEE("'?'と'#'の数が正しく対応していません");
+            return stack.ReduceAll();
+        }
+        
+		#endregion
+
+		/// <summary>
+        /// 式解決用クラス
+        /// </summary>
+        private class TermStack
+        {
+            /// <summary>
+            /// 次に来るべきものの種類。
+            /// (前置)単項演算子か値待ちなら0、二項・三項演算子待ちなら1、値待ちなら2、++、--、!に対応する値待ちの場合は3。
+            /// </summary>
+            int state;
+            bool hasBefore;
+            bool hasAfter;
+            bool waitAfter;
+            Stack<Object> stack = new Stack<Object>();
+            public void Add(OperatorCode op)
+            {
+                if (state == 2 || state == 3)
+                    throw new CodeEE("Unrecognized syntax");
+                if (state == 0)
+                {
+                    if (!OperatorManager.IsUnary(op))
+                        throw new CodeEE("Unrecognized syntax");
+                    stack.Push(op);
+                    if (op == OperatorCode.Plus || op == OperatorCode.Minus || op == OperatorCode.BitNot)
+                        state = 2;
+                    else
+                        state = 3;
+                    return;
+                }
+                if (state == 1)
+                {
+                    //後置単項演算子の場合は特殊処理へ
+                    if (OperatorManager.IsUnaryAfter(op))
+                    {
+                        if (hasAfter)
+                        {
+                            hasAfter = false;
+                            throw new CodeEE("後置の単項演算子が複数存在しています");
+                        }
+                        if (hasBefore)
+                        {
+                            hasBefore = false;
+                            throw new CodeEE("インクリメント・デクリメントを前置・後置両方同時に使うことはできません");
+                        }
+                        stack.Push(op);
+                        reduceUnaryAfter();
+                        //前置単項演算子が処理を待っている場合はここで解決
+                        if (waitAfter)
+                            reduceUnary();
+                        hasBefore = false;
+                        hasAfter = true;
+                        waitAfter = false;
+                        return;
+                    }
+                    if (!OperatorManager.IsBinary(op) && !OperatorManager.IsTernary(op))
+                        throw new CodeEE("Unrecognized syntax");
+                    //先に未解決の前置演算子解決
+                    if (waitAfter)
+                        reduceUnary();
+                    int priority = OperatorManager.GetPriority(op);
+                    //直前の計算の優先度が同じか高いなら還元。
+                    while (lastPriority() >= priority)
+                    {
+                        reduceLastThree();
+                    }
+                    stack.Push(op);
+                    state = 0;
+                    waitAfter = false;
+                    hasBefore = false;
+                    hasAfter = false;
+                    return;
+                }
+                throw new CodeEE("Unrecognized syntax");
+            }
+            public void Add(Int64 i) { Add(new SingleTerm(i)); }
+            public void Add(string s) { Add(new SingleTerm(s)); }
+            public void Add(IOperandTerm term)
+            {
+                stack.Push(term);
+                if (state == 1)
+                    throw new CodeEE("Unrecognized syntax");
+                if (state == 2)
+                    waitAfter = true;
+                if (state == 3)
+                {
+                    reduceUnary();
+                    hasBefore = true;
+                }
+                state = 1;
+            }
+
+
+            private int lastPriority()
+            {
+                if (stack.Count < 3)
+                    return -1;
+                object temp = stack.Pop();
+                OperatorCode opCode = (OperatorCode)stack.Peek();
+                int priority = OperatorManager.GetPriority(opCode);
+                stack.Push(temp);
+                return priority;
+            }
+
+            public IOperandTerm ReduceAll()
+            {
+                if (stack.Count == 0)
+                    return null;
+                if (state != 1)
+                    throw new CodeEE("Unrecognized syntax");
+                //単項演算子の待ちが未解決の時はここで解決
+                if (waitAfter)
+                    reduceUnary();
+                waitAfter = false;
+                hasBefore = false;
+                hasAfter = false;
+                while (stack.Count > 1)
+                {
+                    reduceLastThree();
+                }
+                IOperandTerm retTerm = (IOperandTerm)stack.Pop();
+                return retTerm;
+            }
+
+            private void reduceUnary()
+            {
+                //if (stack.Count < 2)
+                //    throw new ExeEE("不正な時期の呼び出し");
+                IOperandTerm operand = (IOperandTerm)stack.Pop();
+                OperatorCode op = (OperatorCode)stack.Pop();
+                IOperandTerm newTerm = OperatorMethodManager.ReduceUnaryTerm(op, operand);
+                stack.Push(newTerm);
+            }
+
+            private void reduceUnaryAfter()
+            {
+                //if (stack.Count < 2)
+                //    throw new ExeEE("不正な時期の呼び出し");
+                OperatorCode op = (OperatorCode)stack.Pop();
+                IOperandTerm operand = (IOperandTerm)stack.Pop();
+                
+                IOperandTerm newTerm = OperatorMethodManager.ReduceUnaryAfterTerm(op, operand);
+                stack.Push(newTerm);
+				
+            }
+            private void reduceLastThree()
+            {
+                //if (stack.Count < 2)
+                //    throw new ExeEE("不正な時期の呼び出し");
+                IOperandTerm right = (IOperandTerm)stack.Pop();//後から入れたほうが右側
+                OperatorCode op = (OperatorCode)stack.Pop();
+                IOperandTerm left = (IOperandTerm)stack.Pop();
+                if (OperatorManager.IsTernary(op))
+                {
+                    if (stack.Count > 1)
+                    {
+                        reduceTernary(left, right, op);
+                        return;
+                    }
+                    throw new CodeEE("式の数が不足しています");
+                }
+                
+                IOperandTerm newTerm = OperatorMethodManager.ReduceBinaryTerm(op, left, right);
+                stack.Push(newTerm);
+			}
+
+            private void reduceTernary(IOperandTerm left, IOperandTerm right, OperatorCode op)
+            {
+                OperatorCode newOp = (OperatorCode)stack.Pop();
+				IOperandTerm newLeft = (IOperandTerm)stack.Pop();
+				
+                IOperandTerm newTerm = OperatorMethodManager.ReduceTernaryTerm(newOp, newLeft, left, right);
+                stack.Push(newTerm);
+            }
+
+			SingleTerm GetSingle(IOperandTerm oprand)
+			{
+				return (SingleTerm)oprand;
+			}
+        }
+
+    }
+}

+ 44 - 0
NTERA/Game/GameData/Expression/IOperandTerm.cs

@@ -0,0 +1,44 @@
+using System;
+
+namespace MinorShift.Emuera.GameData.Expression
+{
+	internal abstract class IOperandTerm
+	{
+        public IOperandTerm(Type t)
+        {
+            type = t;
+        }
+		public Type GetOperandType()
+        {
+            return type;
+        }
+
+        public virtual Int64 GetIntValue(ExpressionMediator exm)
+        {
+            return 0;
+        }
+        public virtual string GetStrValue(ExpressionMediator exm, bool translate=false)
+        {
+            return "";
+        } 
+        public virtual SingleTerm GetValue(ExpressionMediator exm, bool tryTranslate =false)
+        {
+	        if (type == typeof(Int64))
+                return new SingleTerm(0);
+	        return new SingleTerm("");
+        }
+        public bool IsInteger => type == typeof(Int64);
+
+		public bool IsString => type == typeof(string);
+		readonly Type type;
+        
+		/// <summary>
+		/// 定数を解体して可能ならSingleTerm化する
+		/// defineの都合上、2回以上呼ばれる可能性がある
+		/// </summary>
+        public virtual IOperandTerm Restructure(ExpressionMediator exm, bool tryTranslate=false)
+        {
+			return this;
+        }
+	}
+}

+ 130 - 0
NTERA/Game/GameData/Expression/OperatorCode.cs

@@ -0,0 +1,130 @@
+using System.Collections.Generic;
+
+namespace MinorShift.Emuera.GameData.Expression
+{
+	internal enum OperatorCode
+	{
+		
+		//単項 > "*/%" > "+-" > 比較                > ビット演算  > 論理演算 > 代入
+		//xx   > 90    > 80   > 65,60(不等価優先)   > 50          > 40       > xx
+		//優先順は本家に準拠
+		NULL = 0,
+		__PRIORITY_MASK__ = 0xFF,
+		__UNARY__ = 0x10000,//単項
+		__BINARY__ =  0x20000,//2項
+        __TERNARY__ = 0x40000,//3項
+		__UNARY_AFTER__ = 0x80000,//後置単項
+		Plus = 0x0100 + 0x80 | __UNARY__ | __BINARY__,//"+"単項可
+		Minus = 0x0200 + 0x80 | __UNARY__ | __BINARY__,//"-"
+		Mult = 0x0300 + 0x90 | __BINARY__,//"*"
+		Div = 0x0400 + 0x90 | __BINARY__,//"/"
+		Mod = 0x0500 + 0x90 | __BINARY__,//"%"
+		Equal = 0x0600 + 0x60 | __BINARY__,//"=="
+		Greater = 0x0700 + 0x65 | __BINARY__,//">"
+		Less = 0x0800 + 0x65 | __BINARY__,//"<"
+		GreaterEqual = 0x0900 + 0x65 | __BINARY__,//">="
+		LessEqual = 0x0A00 + 0x65 | __BINARY__,//"<="
+		NotEqual = 0x0B00 + 0x60 | __BINARY__,//"!="
+        Increment = 0x2000 | __UNARY__ | __UNARY_AFTER__,//"++"
+        Decrement = 0x2100 | __UNARY__ | __UNARY_AFTER__,//"--"
+
+		And = 0x0C00 + 0x40 | __BINARY__,//"&&"
+		Or = 0x0D00 + 0x40 | __BINARY__,//"||"
+        Xor = 0x1500 + 0x40 | __BINARY__,//"^^"
+        Nand = 0x1600 + 0x40 | __BINARY__,//"!&"
+        Nor = 0x1700 + 0x40 | __BINARY__,//"!^"
+		BitAnd = 0x0E00 + 0x50 | __BINARY__,//"&"
+		BitOr = 0x0F00 + 0x50 | __BINARY__,//"|"
+		BitXor = 0x1000 + 0x50 | __BINARY__,//"^"、優先順位は&と|の中間。
+		Not = 0x1100 | __UNARY__,//"!"単項
+		BitNot = 0x1200 | __UNARY__,//"~"単項
+		RightShift = 0x1300 + 0x70 | __BINARY__,//">>"
+		LeftShift = 0x1400 + 0x70 | __BINARY__,//"<<"
+
+        Ternary_a = 0x1800 + 0x05 | __TERNARY__,//"?"、三項演算子
+        Ternary_b = 0x1900 + 0x10 | __TERNARY__,//"#"、三項演算子区切り":"が使えないのでかわり
+
+
+		Assignment = 0x0100 + 0xFE,//"="
+		AssignmentStr = 0x0200 + 0xFE//"'="
+	}
+	internal static class OperatorManager
+	{
+
+		static readonly Dictionary<string, OperatorCode> opDictionary;
+		static OperatorManager()
+		{
+		
+			opDictionary = new Dictionary<string, OperatorCode>();
+			opDictionary.Add("+", OperatorCode.Plus);
+			opDictionary.Add("-", OperatorCode.Minus);
+			opDictionary.Add("*", OperatorCode.Mult);
+			opDictionary.Add("/", OperatorCode.Div);
+			opDictionary.Add("%", OperatorCode.Mod);
+			opDictionary.Add("==", OperatorCode.Equal);
+			opDictionary.Add(">", OperatorCode.Greater);
+			opDictionary.Add("<", OperatorCode.Less);
+			opDictionary.Add(">=", OperatorCode.GreaterEqual);
+			opDictionary.Add("<=", OperatorCode.LessEqual);
+			opDictionary.Add("!=", OperatorCode.NotEqual);
+			opDictionary.Add("&&", OperatorCode.And);
+			opDictionary.Add("||", OperatorCode.Or);
+            opDictionary.Add("^^", OperatorCode.Xor);
+            opDictionary.Add("!&", OperatorCode.Nand);
+            opDictionary.Add("!|", OperatorCode.Nor);
+            opDictionary.Add("&", OperatorCode.BitAnd);
+			opDictionary.Add("|", OperatorCode.BitOr);
+			opDictionary.Add("!", OperatorCode.Not);
+			opDictionary.Add("^", OperatorCode.BitXor);
+			opDictionary.Add("~", OperatorCode.BitNot);
+            opDictionary.Add("?", OperatorCode.Ternary_a);
+            opDictionary.Add("#", OperatorCode.Ternary_b);
+			opDictionary.Add(">>", OperatorCode.RightShift);
+			opDictionary.Add("<<", OperatorCode.LeftShift);
+            opDictionary.Add("++", OperatorCode.Increment);
+            opDictionary.Add("--", OperatorCode.Decrement);
+
+			opDictionary.Add("=", OperatorCode.Assignment);
+			opDictionary.Add("'=", OperatorCode.AssignmentStr);
+		}
+
+		public static string ToOperatorString(OperatorCode op)
+		{
+			if (op == OperatorCode.NULL)
+				return "";
+			foreach(KeyValuePair<string, OperatorCode> pair in opDictionary)
+			{
+				if(op == pair.Value)
+					return pair.Key;
+			}
+			return "";
+		}
+
+		public static bool IsUnary(OperatorCode type)
+		{
+			return ((type & OperatorCode.__UNARY__) == OperatorCode.__UNARY__);
+		}
+        public static bool IsUnaryAfter(OperatorCode type)
+        {
+            return ((type & OperatorCode.__UNARY_AFTER__) == OperatorCode.__UNARY_AFTER__);
+        }
+        public static bool IsBinary(OperatorCode type)
+		{
+			return ((type & OperatorCode.__BINARY__) == OperatorCode.__BINARY__);
+		}
+        public static bool IsTernary(OperatorCode type)
+        {
+            return ((type & OperatorCode.__TERNARY__) == OperatorCode.__TERNARY__);
+        }
+
+		/// <summary>
+		/// 大きい方が優先度が高い。 '&' < '+' < '*'等
+		/// </summary>
+		/// <param name="type"></param>
+		/// <returns></returns>
+		public static int GetPriority(OperatorCode type)
+		{
+			return (int)(type & OperatorCode.__PRIORITY_MASK__);
+		}
+	}
+}

+ 824 - 0
NTERA/Game/GameData/Expression/OperatorMethod.cs

@@ -0,0 +1,824 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using MinorShift.Emuera.GameData.Function;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameData.Expression
+{
+	/// <summary>
+	/// 引数のチェック、戻り値の型チェック等は全て呼び出し元が責任を負うこと。
+	/// </summary>
+	internal abstract class OperatorMethod : FunctionMethod
+	{
+		public OperatorMethod()
+		{
+			argumentTypeArray = null;
+		}
+		public override string CheckArgumentType(string name, IOperandTerm[] arguments) { throw new ExeEE("型チェックは呼び出し元が行うこと"); }
+	}
+
+	internal static class OperatorMethodManager
+	{
+		static readonly Dictionary<OperatorCode, OperatorMethod> unaryDic = new Dictionary<OperatorCode, OperatorMethod>();
+		static readonly Dictionary<OperatorCode, OperatorMethod> unaryAfterDic = new Dictionary<OperatorCode, OperatorMethod>();
+		static readonly Dictionary<OperatorCode, OperatorMethod> binaryIntIntDic = new Dictionary<OperatorCode, OperatorMethod>();
+		static readonly Dictionary<OperatorCode, OperatorMethod> binaryStrStrDic = new Dictionary<OperatorCode, OperatorMethod>();
+		static readonly OperatorMethod binaryMultIntStr;
+		static readonly OperatorMethod ternaryIntIntInt;
+		static readonly OperatorMethod ternaryIntStrStr;
+
+		static OperatorMethodManager()
+		{
+			unaryDic[OperatorCode.Plus] = new PlusInt();
+			unaryDic[OperatorCode.Minus] = new MinusInt();
+			unaryDic[OperatorCode.Not] = new NotInt();
+			unaryDic[OperatorCode.BitNot] = new BitNotInt();
+			unaryDic[OperatorCode.Increment] = new IncrementInt();
+			unaryDic[OperatorCode.Decrement] = new DecrementInt();
+
+			unaryAfterDic[OperatorCode.Increment] = new IncrementAfterInt();
+			unaryAfterDic[OperatorCode.Decrement] = new DecrementAfterInt();
+
+			binaryIntIntDic[OperatorCode.Plus] = new PlusIntInt();
+			binaryIntIntDic[OperatorCode.Minus] = new MinusIntInt();
+			binaryIntIntDic[OperatorCode.Mult] = new MultIntInt();
+			binaryIntIntDic[OperatorCode.Div] = new DivIntInt();
+			binaryIntIntDic[OperatorCode.Mod] = new ModIntInt();
+			binaryIntIntDic[OperatorCode.Equal] = new EqualIntInt();
+			binaryIntIntDic[OperatorCode.Greater] = new GreaterIntInt();
+			binaryIntIntDic[OperatorCode.Less] = new LessIntInt();
+			binaryIntIntDic[OperatorCode.GreaterEqual] = new GreaterEqualIntInt();
+			binaryIntIntDic[OperatorCode.LessEqual] = new LessEqualIntInt();
+			binaryIntIntDic[OperatorCode.NotEqual] = new NotEqualIntInt();
+			binaryIntIntDic[OperatorCode.And] = new AndIntInt();
+			binaryIntIntDic[OperatorCode.Or] = new OrIntInt();
+			binaryIntIntDic[OperatorCode.Xor] = new XorIntInt();
+			binaryIntIntDic[OperatorCode.Nand] = new NandIntInt();
+			binaryIntIntDic[OperatorCode.Nor] = new NorIntInt();
+			binaryIntIntDic[OperatorCode.BitAnd] = new BitAndIntInt();
+			binaryIntIntDic[OperatorCode.BitOr] = new BitOrIntInt();
+			binaryIntIntDic[OperatorCode.BitXor] = new BitXorIntInt();
+			binaryIntIntDic[OperatorCode.RightShift] = new RightShiftIntInt();
+			binaryIntIntDic[OperatorCode.LeftShift] = new LeftShiftIntInt();
+
+			binaryStrStrDic[OperatorCode.Plus] = new PlusStrStr();
+			binaryStrStrDic[OperatorCode.Equal] = new EqualStrStr();
+			binaryStrStrDic[OperatorCode.Greater] = new GreaterStrStr();
+			binaryStrStrDic[OperatorCode.Less] = new LessStrStr();
+			binaryStrStrDic[OperatorCode.GreaterEqual] = new GreaterEqualStrStr();
+			binaryStrStrDic[OperatorCode.LessEqual] = new LessEqualStrStr();
+			binaryStrStrDic[OperatorCode.NotEqual] = new NotEqualStrStr();
+
+			binaryMultIntStr = new MultStrInt();
+			ternaryIntIntInt = new TernaryIntIntInt();
+			ternaryIntStrStr = new TernaryIntStrStr();
+		}
+		
+		
+		
+		public static IOperandTerm ReduceUnaryTerm(OperatorCode op, IOperandTerm o1)
+		{
+            OperatorMethod method = null;
+			if (op == OperatorCode.Increment || op == OperatorCode.Decrement)
+			{
+				VariableTerm var = o1 as VariableTerm;
+				if (var == null)
+					throw new CodeEE("変数以外をインクリメントすることはできません");
+				if (var.Identifier.IsConst)
+					throw new CodeEE("変更できない変数をインクリメントすることはできません");
+			}
+			if (o1.GetOperandType() == typeof(Int64))
+			{
+				if (op == OperatorCode.Plus)
+					return o1;
+				if (unaryDic.ContainsKey(op))
+					method = unaryDic[op];
+			}
+			if(method != null)
+				return new FunctionMethodTerm(method, new[] { o1 });
+            string errMes = "";
+            if (o1.GetOperandType() == typeof(Int64))
+                errMes += "数値型";
+            else if (o1.GetOperandType() == typeof(string))
+                errMes += "文字列型";
+            else
+                errMes += "不定型";
+            errMes += "に単項演算子\'" + OperatorManager.ToOperatorString(op) + "\'は適用できません";
+            throw new CodeEE(errMes);
+		}
+		
+		public static IOperandTerm ReduceUnaryAfterTerm(OperatorCode op, IOperandTerm o1)
+		{
+            OperatorMethod method = null;
+			if (op == OperatorCode.Increment || op == OperatorCode.Decrement)
+			{
+				VariableTerm var = o1 as VariableTerm;
+				if (var == null)
+					throw new CodeEE("変数以外をインクリメントすることはできません");
+				if (var.Identifier.IsConst)
+					throw new CodeEE("変更できない変数をインクリメントすることはできません");
+			}
+			if (o1.GetOperandType() == typeof(Int64))
+			{
+				if (unaryAfterDic.ContainsKey(op))
+					method = unaryAfterDic[op];
+			}
+			if (method != null)
+				return new FunctionMethodTerm(method, new[] { o1 });
+            string errMes = "";
+            if (o1.GetOperandType() == typeof(Int64))
+                errMes += "数値型";
+            else if (o1.GetOperandType() == typeof(string))
+                errMes += "文字列型";
+            else
+                errMes += "不定型";
+            errMes += "に後置単項演算子\'" + OperatorManager.ToOperatorString(op) + "\'は適用できません";
+            throw new CodeEE(errMes);
+		}
+		
+		public static IOperandTerm ReduceBinaryTerm(OperatorCode op, IOperandTerm left, IOperandTerm right)
+		{
+            OperatorMethod method = null;
+			if ((left.GetOperandType() == typeof(Int64)) && (right.GetOperandType() == typeof(Int64)))
+			{
+				if (binaryIntIntDic.ContainsKey(op))
+					method = binaryIntIntDic[op];
+			}
+			else if ((left.GetOperandType() == typeof(string)) && (right.GetOperandType() == typeof(string)))
+			{
+				if (binaryStrStrDic.ContainsKey(op))
+					method = binaryStrStrDic[op];
+			}
+			else if (((left.GetOperandType() == typeof(Int64)) && (right.GetOperandType() == typeof(string)))
+				 || ((left.GetOperandType() == typeof(string)) && (right.GetOperandType() == typeof(Int64))))
+			{
+				if (op == OperatorCode.Mult)
+					method = binaryMultIntStr;
+			}
+			if (method != null)
+				return new FunctionMethodTerm(method, new[] { left, right });
+			string errMes = "";
+                if (left.GetOperandType() == typeof(Int64))
+                    errMes += "数値型と";
+                else if (left.GetOperandType() == typeof(string))
+                    errMes += "文字列型と";
+                else
+                    errMes += "不定型と";
+                if (right.GetOperandType() == typeof(Int64))
+                    errMes += "数値型の";
+                else if (right.GetOperandType() == typeof(string))
+                    errMes += "文字列型の";
+                else
+                    errMes += "不定型の";
+                errMes += "演算に二項演算子\'" + OperatorManager.ToOperatorString(op) + "\'は適用できません";
+                throw new CodeEE(errMes);
+		}
+		
+		public static IOperandTerm ReduceTernaryTerm(OperatorCode op, IOperandTerm o1, IOperandTerm o2, IOperandTerm o3)
+		{
+            OperatorMethod method = null;
+			if ((o1.GetOperandType() == typeof(Int64)) && (o2.GetOperandType() == typeof(Int64)) && (o3.GetOperandType() == typeof(Int64)))
+				method = ternaryIntIntInt;
+			else if ((o1.GetOperandType() == typeof(Int64)) && (o2.GetOperandType() == typeof(string)) && (o3.GetOperandType() == typeof(string)))
+				method = ternaryIntStrStr;
+			if (method != null)
+				return new FunctionMethodTerm(method, new[] { o1, o2, o3 });
+			throw new CodeEE("三項演算子の使用法が不正です");
+			
+		}
+
+
+
+
+
+
+
+
+
+
+		#region OperatorMethod SubClasses
+
+		private sealed class PlusIntInt : OperatorMethod
+		{
+			public PlusIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				return arguments[0].GetIntValue(exm) + arguments[1].GetIntValue(exm);
+			}
+		}
+
+		private sealed class PlusStrStr : OperatorMethod
+		{
+			public PlusStrStr()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(string);
+				argumentTypeArray = new[] { typeof(string), typeof(string) };
+			}
+
+			public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+			{
+				return arguments[0].GetStrValue(exm, tryTranslate) + arguments[1].GetStrValue(exm, tryTranslate); // JVN: Would be a great idea to attempt to translate both sides instead of just one here
+			}
+		}
+
+		private sealed class MinusIntInt : OperatorMethod
+		{
+			public MinusIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				return arguments[0].GetIntValue(exm) - arguments[1].GetIntValue(exm);
+			}
+		}
+
+		private sealed class MultIntInt : OperatorMethod
+		{
+			public MultIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				return arguments[0].GetIntValue(exm) * arguments[1].GetIntValue(exm);
+			}
+		}
+
+		private sealed class MultStrInt : OperatorMethod
+		{
+			public MultStrInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(string);
+			}
+			public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+			{
+				Int64 value = 0;
+				string str = null;
+				if (arguments[0].GetOperandType() == typeof(Int64))
+				{
+					value = arguments[0].GetIntValue(exm);
+					str = arguments[1].GetStrValue(exm, tryTranslate);
+				}
+				else
+				{
+					str = arguments[0].GetStrValue(exm, tryTranslate);
+					value = arguments[1].GetIntValue(exm);
+				}
+				if (value < 0)
+					throw new CodeEE("文字列に負の値(" + value + ")を乗算しようとしました");
+				if (value >= 10000)
+					throw new CodeEE("文字列に10000以上の値(" + value + ")を乗算しようとしました");
+				if ((str == "") || (value == 0))
+					return "";
+				StringBuilder builder = new StringBuilder();
+				builder.Capacity = str.Length * (int)value;
+				for (int i = 0; i < value; i++)
+				{
+					builder.Append(str);
+				}
+				return builder.ToString();
+			}
+		}
+
+		private sealed class DivIntInt : OperatorMethod
+		{
+			public DivIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+	        {
+				Int64 right = arguments[1].GetIntValue(exm);
+				if (right == 0)
+					throw new CodeEE("0による除算が行なわれました");
+				return arguments[0].GetIntValue(exm) / right;
+			}
+		}
+
+		private sealed class ModIntInt : OperatorMethod
+		{
+			public ModIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+	        {
+				Int64 right = arguments[1].GetIntValue(exm);
+				if (right == 0)
+					throw new CodeEE("0による除算が行なわれました");
+				return arguments[0].GetIntValue(exm) % right;
+			}
+		}
+
+
+		private sealed class EqualIntInt : OperatorMethod
+		{
+			public EqualIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				if (arguments[0].GetIntValue(exm) == arguments[1].GetIntValue(exm))
+					return 1L;
+				return 0L;
+			}
+
+		}
+
+		private sealed class EqualStrStr : OperatorMethod
+		{
+			public EqualStrStr()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				if (arguments[0].GetStrValue(exm) == arguments[1].GetStrValue(exm))
+					return 1L;
+				return 0L;
+			}
+		}
+
+		private sealed class NotEqualIntInt : OperatorMethod
+		{
+			public NotEqualIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				if (arguments[0].GetIntValue(exm) != arguments[1].GetIntValue(exm))
+					return 1L;
+				return 0L;
+			}
+		}
+
+		private sealed class NotEqualStrStr : OperatorMethod
+		{
+			public NotEqualStrStr()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				if (arguments[0].GetStrValue(exm) != arguments[1].GetStrValue(exm))
+					return 1L;
+				return 0L;
+			}
+
+		}
+
+		private sealed class GreaterIntInt : OperatorMethod
+		{
+			public GreaterIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				if (arguments[0].GetIntValue(exm) > arguments[1].GetIntValue(exm))
+					return 1L;
+				return 0L;
+			}
+		}
+
+		private sealed class GreaterStrStr : OperatorMethod
+		{
+			public GreaterStrStr()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				int c = string.Compare(arguments[0].GetStrValue(exm), arguments[1].GetStrValue(exm), Config.SCExpression);
+				if (c > 0)
+					return 1L;
+				return 0L;
+			}
+		}
+		private sealed class LessIntInt : OperatorMethod
+		{
+			public LessIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				if (arguments[0].GetIntValue(exm) < arguments[1].GetIntValue(exm))
+					return 1L;
+				return 0L;
+			}
+		}
+		private sealed class LessStrStr : OperatorMethod
+		{
+			public LessStrStr()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				int c = string.Compare(arguments[0].GetStrValue(exm), arguments[1].GetStrValue(exm), Config.SCExpression);
+				if (c < 0)
+					return 1L;
+				return 0L;
+			}
+
+		}
+
+		private sealed class GreaterEqualIntInt : OperatorMethod
+		{
+			public GreaterEqualIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				if (arguments[0].GetIntValue(exm) >= arguments[1].GetIntValue(exm))
+					return 1L;
+				return 0L;
+			}
+		}
+
+		private sealed class GreaterEqualStrStr : OperatorMethod
+		{
+			public GreaterEqualStrStr()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				int c = string.Compare(arguments[0].GetStrValue(exm), arguments[1].GetStrValue(exm), Config.SCExpression);
+				if (c < 0)
+					return 1L;
+				return 0L;
+			}
+		}
+		private sealed class LessEqualIntInt : OperatorMethod
+		{
+			public LessEqualIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				if (arguments[0].GetIntValue(exm) <= arguments[1].GetIntValue(exm))
+					return 1L;
+				return 0L;
+			}
+
+		}
+		private sealed class LessEqualStrStr : OperatorMethod
+		{
+			public LessEqualStrStr()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				int c = string.Compare(arguments[0].GetStrValue(exm), arguments[1].GetStrValue(exm), Config.SCExpression);
+				if (c < 0)
+					return 1L;
+				return 0L;
+			}
+		}
+
+		private sealed class AndIntInt : OperatorMethod
+		{
+			public AndIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				if ((arguments[0].GetIntValue(exm) != 0) && (arguments[1].GetIntValue(exm) != 0))
+					return 1L;
+				return 0L;
+			}
+
+		}
+
+		private sealed class OrIntInt : OperatorMethod
+		{
+			public OrIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				if ((arguments[0].GetIntValue(exm) != 0) || (arguments[1].GetIntValue(exm) != 0))
+					return 1L;
+				return 0L;
+			}
+		}
+
+		private sealed class XorIntInt : OperatorMethod
+		{
+			public XorIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				Int64 i1 = arguments[0].GetIntValue(exm);
+				Int64 i2 = arguments[1].GetIntValue(exm);
+				if (((i1 == 0) && (i2 != 0)) || ((i1 != 0) && (i2 == 0)))
+					return 1L;
+				return 0L;
+			}
+
+		}
+
+		private sealed class NandIntInt : OperatorMethod
+		{
+			public NandIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				if ((arguments[0].GetIntValue(exm) == 0) || (arguments[1].GetIntValue(exm) == 0))
+					return 1L;
+				return 0L;
+			}
+
+		}
+
+		private sealed class NorIntInt : OperatorMethod
+		{
+			public NorIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				if ((arguments[0].GetIntValue(exm) == 0) && (arguments[1].GetIntValue(exm) == 0))
+					return 1L;
+				return 0L;
+			}
+		}
+
+		private sealed class BitAndIntInt : OperatorMethod
+		{
+			public BitAndIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				return arguments[0].GetIntValue(exm) & arguments[1].GetIntValue(exm);
+			}
+		}
+
+		private sealed class BitOrIntInt : OperatorMethod
+		{
+			public BitOrIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				return arguments[0].GetIntValue(exm) | arguments[1].GetIntValue(exm);
+			}
+		}
+
+		private sealed class BitXorIntInt : OperatorMethod
+		{
+			public BitXorIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				return arguments[0].GetIntValue(exm) ^ arguments[1].GetIntValue(exm);
+			}
+		}
+
+		private sealed class RightShiftIntInt : OperatorMethod
+		{
+			public RightShiftIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				return arguments[0].GetIntValue(exm) >> (Int32)(arguments[1].GetIntValue(exm));
+			}
+		}
+
+		private sealed class LeftShiftIntInt : OperatorMethod
+		{
+			public LeftShiftIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				return arguments[0].GetIntValue(exm) << (Int32)(arguments[1].GetIntValue(exm));
+			}
+		}
+
+		private sealed class PlusInt : OperatorMethod
+		{
+			public PlusInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				return arguments[0].GetIntValue(exm);
+			}
+		}
+
+		private sealed class MinusInt : OperatorMethod
+		{
+			public MinusInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				return -arguments[0].GetIntValue(exm);
+			}
+		}
+
+		private sealed class NotInt : OperatorMethod
+		{
+			public NotInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				if (arguments[0].GetIntValue(exm) == 0)
+					return 1L;
+				return 0L;
+			}
+		}
+		private sealed class BitNotInt : OperatorMethod
+		{
+			public BitNotInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				return ~arguments[0].GetIntValue(exm);
+			}
+		}
+
+		private sealed class IncrementInt : OperatorMethod
+		{
+			public IncrementInt()
+			{
+				CanRestructure = false;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				VariableTerm var = (VariableTerm)arguments[0];
+				return var.PlusValue(1L, exm);
+			}
+		}
+		private sealed class DecrementInt : OperatorMethod
+		{
+			public DecrementInt()
+			{
+				CanRestructure = false;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				VariableTerm var = (VariableTerm)arguments[0];
+				return var.PlusValue(-1L, exm);
+			}
+		}
+		private sealed class IncrementAfterInt : OperatorMethod
+		{
+			public IncrementAfterInt()
+			{
+				CanRestructure = false;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				VariableTerm var = (VariableTerm)arguments[0];
+				return var.PlusValue(1L, exm) - 1;
+			}
+		}
+
+		private sealed class DecrementAfterInt : OperatorMethod
+		{
+			public DecrementAfterInt()
+			{
+				CanRestructure = false;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				VariableTerm var = (VariableTerm)arguments[0];
+				return var.PlusValue(-1L, exm) + 1;
+			}
+		}
+
+
+		private sealed class TernaryIntIntInt : OperatorMethod
+		{
+			public TernaryIntIntInt()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(Int64);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				return (arguments[0].GetIntValue(exm) != 0) ? arguments[1].GetIntValue(exm) : arguments[2].GetIntValue(exm);
+			}
+		}
+
+		private sealed class TernaryIntStrStr : OperatorMethod
+		{
+			public TernaryIntStrStr()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(string);
+			}
+
+			public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+			{
+				return (arguments[0].GetIntValue(exm) != 0) ? arguments[1].GetStrValue(exm) : arguments[2].GetStrValue(exm);
+			}
+		}
+
+		#endregion
+	}
+}

+ 132 - 0
NTERA/Game/GameData/Expression/Term.cs

@@ -0,0 +1,132 @@
+using System;
+using MinorShift.Emuera.GameData.Variable;
+
+namespace MinorShift.Emuera.GameData.Expression
+{
+
+    internal sealed class NullTerm : IOperandTerm 
+    {
+        public NullTerm(Int64 i)
+            : base(typeof(Int64))
+        {
+        }
+
+        public NullTerm(string s)
+            : base(typeof(string))
+        {
+        }
+    }
+
+	/// <summary>
+	/// 項。一単語だけ。
+	/// </summary>
+	internal sealed class SingleTerm : IOperandTerm
+	{
+
+        public SingleTerm(bool i)
+            : base(typeof(Int64))
+		{
+			if (i)
+				iValue = 1;
+			else
+				iValue = 0;
+		}
+        public SingleTerm(Int64 i)
+            : base(typeof(Int64))
+		{
+			iValue = i;
+		}
+        public SingleTerm(string s)
+            : base(typeof(string))
+		{
+			sValue = s;
+		}
+		readonly Int64 iValue;
+		string sValue;
+
+        public override long GetIntValue(ExpressionMediator exm)
+        {
+            return iValue;
+        }
+        public override string GetStrValue(ExpressionMediator exm, bool translate=false)
+        {
+            //Modified by Bartoum
+            //PRINTS go through here.
+            if (exm != null && exm.Process != null && exm.Process.getCurrentLine != null)
+            {
+                string name = exm.Process.getCurrentLine.ToString();
+                name = Translation.searchParentFile(name);
+                sValue = Translation.translate(sValue, name, translate);
+            }
+            return sValue;
+        }
+        public override SingleTerm GetValue(ExpressionMediator exm, bool tryTranslate =false)
+        {
+            return this;
+        }
+		public string Str
+		{
+			get => sValue;
+			set // JVN: Set method needed to make things work smoother for PARAM stuff
+            {
+                sValue = value;
+            }
+		}
+
+		public Int64 Int => iValue;
+
+		public override string ToString()
+		{
+			if (GetOperandType() == typeof(Int64))
+				return iValue.ToString();
+            if (GetOperandType() == typeof(string))
+				return sValue;
+			return base.ToString();
+		}
+		
+        public override IOperandTerm Restructure(ExpressionMediator exm, bool tryTranslate=false)
+        {
+			return this;
+        }
+	}
+	/// <summary>
+	/// 項。一単語だけ。
+	/// </summary>
+	internal sealed class StrFormTerm : IOperandTerm
+	{
+		public StrFormTerm(StrForm sf)
+			: base(typeof(string))
+		{
+			sfValue = sf;
+		}
+		readonly StrForm sfValue;
+
+		public StrForm StrForm => sfValue;
+
+		public override string GetStrValue(ExpressionMediator exm, bool translate=false)
+		{
+            // Bartoum: If the current line containts <nonbutton (for HTML) we translate it.
+            if (exm.Process.getCurrentLine.ToString().Contains("<nonbutton"))
+            {
+                translate = true;
+            }
+            return sfValue.GetString(exm, translate);
+		}
+		public override SingleTerm GetValue(ExpressionMediator exm, bool tryTranslate =false)
+		{
+			return new SingleTerm(sfValue.GetString(exm, tryTranslate));
+		}
+		
+        public override IOperandTerm Restructure(ExpressionMediator exm, bool tryTranslate=false)
+        {
+			sfValue.Restructure(exm);
+			if(sfValue.IsConst)
+				return new SingleTerm(sfValue.GetString(exm, tryTranslate));
+			IOperandTerm term = sfValue.GetIOperandTerm();
+			if(term != null)
+				return term;
+			return this;
+        }
+	}
+
+}

+ 2693 - 0
NTERA/Game/GameData/Function/Creator.Method.cs

@@ -0,0 +1,2693 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Text;
+using System.Reflection;
+using System.Text;
+using System.Text.RegularExpressions;
+using Microsoft.VisualBasic;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.Sub;
+using MinorShift._Library;
+using NTERA.Game.Display;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera.GameData.Function
+{
+
+    internal static partial class FunctionMethodCreator
+    {
+        #region CSVデータ関係
+        private sealed class GetcharaMethod : FunctionMethod
+        {
+            public GetcharaMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                CanRestructure = false;
+            }
+
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                //通常2つ、1つ省略可能で1~2の引数が必要。
+                if (arguments.Length < 1)
+                    return name + "関数には少なくとも1つの引数が必要です";
+                if (arguments.Length > 2)
+                    return name + "関数の引数が多すぎます";
+
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (arguments[0].GetOperandType() != typeof(Int64))
+                    return name + "関数の1番目の引数の型が正しくありません";
+                //2は省略可能
+                if ((arguments.Length == 2) && (arguments[1] != null) && (arguments[1].GetOperandType() != typeof(Int64)))
+                    return name + "関数の2番目の引数の型が正しくありません";
+                return null;
+            }
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 integer = arguments[0].GetIntValue(exm);
+                Int64 chara = -1L;
+
+				if (!Config.CompatiSPChara)
+				{
+					//if ((arguments.Length > 1) && (arguments[1] != null) && (arguments[1].GetIntValue(exm) != 0))
+					return exm.VEvaluator.GetChara(integer);
+				}
+				//以下互換性用の旧処理
+                bool CheckSp = false;
+                if ((arguments.Length > 1) && (arguments[1] != null) && (arguments[1].GetIntValue(exm) != 0))
+                    CheckSp = true;
+                if (CheckSp)
+                {
+                    chara = exm.VEvaluator.GetChara_UseSp(integer, false);
+                    if (chara != -1)
+                        return chara;
+	                return exm.VEvaluator.GetChara_UseSp(integer, true);
+                }
+
+	            return exm.VEvaluator.GetChara_UseSp(integer, false);
+            }
+        }
+
+        private sealed class GetspcharaMethod : FunctionMethod
+        {
+            public GetspcharaMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(Int64) };
+                CanRestructure = false;
+            }
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+				if(!Config.CompatiSPChara)
+					throw new CodeEE("SPキャラ関係の機能は標準では使用できません(互換性オプション「SPキャラを使用する」をONにしてください)");
+                Int64 integer = arguments[0].GetIntValue(exm);
+                return exm.VEvaluator.GetChara_UseSp(integer, true);
+            }
+        }
+
+        private sealed class CsvStrDataMethod : FunctionMethod
+        {
+            CharacterStrData charaStr;
+            public CsvStrDataMethod()
+            {
+                ReturnType = typeof(string);
+				argumentTypeArray = null;
+                charaStr = CharacterStrData.NAME;
+                CanRestructure = true;
+            }
+            public CsvStrDataMethod(CharacterStrData cStr)
+            {
+                ReturnType = typeof(string);
+				argumentTypeArray = null;
+				charaStr = cStr;
+				CanRestructure = true;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                if (arguments.Length < 1)
+                    return name + "関数には少なくとも1つの引数が必要です";
+                if (arguments.Length > 2)
+                    return name + "関数の引数が多すぎます";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (!arguments[0].IsInteger)
+                    return name + "関数の1番目の引数が数値ではありません";
+                if (arguments.Length == 1)
+                    return null;
+                if ((arguments[1] != null) && (arguments[1].GetOperandType() != typeof(Int64)))
+                    return name + "関数の2番目の変数が数値ではありません";
+                return null;
+            }
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+            {
+                long x = arguments[0].GetIntValue(exm);
+				long y = (arguments.Length > 1 && arguments[1] != null) ? arguments[1].GetIntValue(exm) : 0;
+				if (!Config.CompatiSPChara && y != 0)
+					throw new CodeEE("SPキャラ関係の機能は標準では使用できません(互換性オプション「SPキャラを使用する」をONにしてください)");
+                return exm.VEvaluator.GetCharacterStrfromCSVData(x, charaStr, (y != 0), 0);
+            }
+        }
+
+        private sealed class CsvcstrMethod : FunctionMethod
+        {
+            public CsvcstrMethod()
+            {
+                ReturnType = typeof(string);
+                argumentTypeArray = null;
+                CanRestructure = true;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                if (arguments.Length < 2)
+                    return name + "関数には少なくとも2つの引数が必要です";
+                if (arguments.Length > 3)
+                    return name + "関数の引数が多すぎます";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (!arguments[0].IsInteger)
+                    return name + "関数の1番目の引数が数値ではありません";
+                if (arguments[1] == null)
+                    return name + "関数の2番目の引数は省略できません";
+                if (arguments[1].GetOperandType() != typeof(Int64))
+                    return name + "関数の2番目の変数が数値ではありません";
+                if (arguments.Length == 2)
+                    return null;
+                if ((arguments[2] != null) && (arguments[2].GetOperandType() != typeof(Int64)))
+                    return name + "関数の3番目の変数が数値ではありません";
+                return null;
+            }
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+            {
+                long x = arguments[0].GetIntValue(exm);
+                long y = arguments[1].GetIntValue(exm);
+                long z = (arguments.Length == 3 && arguments[2] != null) ? arguments[2].GetIntValue(exm) : 0;
+				if(!Config.CompatiSPChara && z != 0)
+					throw new CodeEE("SPキャラ関係の機能は標準では使用できません(互換性オプション「SPキャラを使用する」をONにしてください)");
+                return exm.VEvaluator.GetCharacterStrfromCSVData(x, CharacterStrData.CSTR, (z != 0), y);
+            }
+        }
+
+        private sealed class CsvDataMethod : FunctionMethod
+        {
+            CharacterIntData charaInt;
+            public CsvDataMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                charaInt = CharacterIntData.BASE;
+                CanRestructure = true;
+            }
+            public CsvDataMethod(CharacterIntData cInt)
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+				charaInt = cInt;
+				CanRestructure = true;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                if (arguments.Length < 2)
+                    return name + "関数には少なくとも2つの引数が必要です";
+                if (arguments.Length > 3)
+                    return name + "関数の引数が多すぎます";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (!arguments[0].IsInteger)
+                    return name + "関数の1番目の引数が数値ではありません";
+                if (arguments[1] == null)
+                    return name + "関数の2番目の引数は省略できません";
+                if (arguments[1].GetOperandType() != typeof(Int64))
+                    return name + "関数の2番目の変数が数値ではありません";
+                if (arguments.Length == 2)
+                    return null;
+                if ((arguments[2] != null) && (arguments[2].GetOperandType() != typeof(Int64)))
+                    return name + "関数の3番目の変数が数値ではありません";
+                return null;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                long x = arguments[0].GetIntValue(exm);
+                long y = arguments[1].GetIntValue(exm);
+                long z = (arguments.Length == 3 && arguments[2] != null) ? arguments[2].GetIntValue(exm) : 0;
+				if(!Config.CompatiSPChara && z != 0)
+					throw new CodeEE("SPキャラ関係の機能は標準では使用できません(互換性オプション「SPキャラを使用する」をONにしてください)");
+                return exm.VEvaluator.GetCharacterIntfromCSVData(x, charaInt, (z != 0), y);
+            }
+        }
+
+        private sealed class FindcharaMethod : FunctionMethod
+        {
+            public FindcharaMethod(bool last)
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                CanRestructure = false;
+                isLast = last;
+            }
+            bool isLast;
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                //通常3つ、1つ省略可能で2~3の引数が必要。
+                if (arguments.Length < 2)
+                    return name + "関数には少なくとも2つの引数が必要です";
+                if (arguments.Length > 4)
+                    return name + "関数の引数が多すぎます";
+
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (!(arguments[0] is VariableTerm))
+                    return name + "関数の1番目の引数の型が正しくありません";
+                if (!(((VariableTerm)arguments[0]).Identifier.IsCharacterData))
+                    return name + "関数の1番目の引数の変数がキャラクタ変数ではありません";
+                if (arguments[1] == null)
+                    return name + "関数の2番目の引数は省略できません";
+                if (arguments[1].GetOperandType() != arguments[0].GetOperandType())
+                    return name + "関数の2番目の引数の型が正しくありません";
+                //3番目は省略可能
+                if ((arguments.Length >= 3) && (arguments[2] != null) && (arguments[2].GetOperandType() != typeof(Int64)))
+                    return name + "関数の3番目の引数の型が正しくありません";
+                //4番目は省略可能
+                if ((arguments.Length >= 4) && (arguments[3] != null) && (arguments[3].GetOperandType() != typeof(Int64)))
+                    return name + "関数の4番目の引数の型が正しくありません";
+                return null;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                VariableTerm vTerm = (VariableTerm)arguments[0];
+                VariableToken varID = vTerm.Identifier;
+
+                Int64 elem = 0;
+                if (vTerm.Identifier.IsArray1D)
+                    elem = vTerm.GetElementInt(1, exm);
+                else if (vTerm.Identifier.IsArray2D)
+                {
+                    elem = vTerm.GetElementInt(1, exm) << 32;
+                    elem += vTerm.GetElementInt(2, exm);
+                }
+                Int64 startindex = 0;
+                Int64 lastindex = exm.VEvaluator.CHARANUM;
+                if (arguments.Length >= 3 && arguments[2] != null)
+                    startindex = arguments[2].GetIntValue(exm);
+                if (arguments.Length >= 4 && arguments[3] != null)
+                    lastindex = arguments[3].GetIntValue(exm);
+                Int64 ret = -1;
+                if (startindex < 0 || startindex >= exm.VEvaluator.CHARANUM)
+                    throw new CodeEE((isLast ? "" : "") + "関数の第3引数(" + startindex + ")はキャラクタ位置の範囲外です");
+                if (lastindex < 0 || lastindex > exm.VEvaluator.CHARANUM)
+                    throw new CodeEE((isLast ? "" : "") + "関数の第4引数(" + lastindex + ")はキャラクタ位置の範囲外です");
+                if (varID.IsString)
+                {
+                    string word = arguments[1].GetStrValue(exm);
+                    ret = exm.VEvaluator.FindChara(varID, elem, word, startindex, lastindex, isLast);
+                }
+                else
+                {
+                    Int64 word = arguments[1].GetIntValue(exm);
+                    ret = exm.VEvaluator.FindChara(varID, elem, word, startindex, lastindex, isLast);
+                }
+                return (ret);
+            }
+        }
+
+        private sealed class ExistCsvMethod : FunctionMethod
+        {
+            public ExistCsvMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                CanRestructure = true;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                if (arguments.Length < 1)
+                    return name + "関数には少なくとも1つの引数が必要です";
+                if (arguments.Length > 2)
+                    return name + "関数の引数が多すぎます";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (!arguments[0].IsInteger)
+                    return name + "関数の1番目の引数が数値ではありません";
+                if (arguments.Length == 1)
+                    return null;
+                if ((arguments[1] != null) && (arguments[1].GetOperandType() != typeof(Int64)))
+                    return name + "関数の2番目の変数が数値ではありません";
+                return null;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 no = arguments[0].GetIntValue(exm);
+                bool isSp =(arguments.Length == 2 && arguments[1] != null) ? (arguments[1].GetIntValue(exm) != 0) : false;
+				if(!Config.CompatiSPChara && isSp)
+					throw new CodeEE("SPキャラ関係の機能は標準では使用できません(互換性オプション「SPキャラを使用する」をONにしてください)");
+
+                return (exm.VEvaluator.ExistCsv(no, isSp));
+            }
+        }
+        #endregion
+
+        #region 汎用処理系
+        private sealed class VarsizeMethod : FunctionMethod
+        {
+            public VarsizeMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                CanRestructure = true;
+				//1808beta009 参照型変数の追加によりちょっと面倒になった
+				HasUniqueRestructure = true;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                if (arguments.Length < 1)
+                    return name + "関数には少なくとも1つの引数が必要です";
+                if (arguments.Length > 2)
+                    return name + "関数の引数が多すぎます";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (!arguments[0].IsString)
+                    return name + "関数の1番目の引数が文字列ではありません";
+                if (arguments[0] is SingleTerm)
+                {
+                    string varName = ((SingleTerm)arguments[0]).Str;
+                    if (varName == "PARAM") ((SingleTerm)arguments[0]).Str = varName = "PALAM"; // JVN: Uses added setter to change PARAM to PALAM internally
+                    if (GlobalStatic.IdentifierDictionary.GetVariableToken(varName, null, true) == null)
+                        return name + "関数の1番目の引数が変数名ではありません";
+                }
+                if (arguments.Length == 1)
+                    return null;
+                if ((arguments[1] != null) && (arguments[1].GetOperandType() != typeof(Int64)))
+                    return name + "関数の2番目の変数が数値ではありません";
+                if (arguments.Length == 2)
+                    return null;
+                return null;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                VariableToken var = GlobalStatic.IdentifierDictionary.GetVariableToken(arguments[0].GetStrValue(exm), null, true);
+                if (var == null)
+                    throw new CodeEE("VARSIZEの1番目の引数(\"" + arguments[0].GetStrValue(exm) + "\")が変数名ではありません");
+                int dim = 0;
+                if (arguments.Length == 2 && arguments[1] != null)
+                    dim = (int)arguments[1].GetIntValue(exm);
+                return (var.GetLength(dim));
+            }
+			public override bool UniqueRestructure(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				arguments[0].Restructure(exm);
+				if (arguments.Length > 1)
+					arguments[1].Restructure(exm);
+				if (arguments[0] is SingleTerm && (arguments.Length == 1 || arguments[1] is SingleTerm))
+				{
+					VariableToken var = GlobalStatic.IdentifierDictionary.GetVariableToken(arguments[0].GetStrValue(exm), null, true);
+					if (var == null || var.IsReference)//可変長の場合は定数化できない
+						return false;
+					return true;
+				}
+				return false;
+			}
+        }
+
+        private sealed class CheckfontMethod : FunctionMethod
+        {
+			public CheckfontMethod()
+			{
+				ReturnType = typeof(Int64);
+				argumentTypeArray = new[] { typeof(string) };
+				CanRestructure = true;//起動中に変わることもそうそうないはず……
+			}
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                string str = arguments[0].GetStrValue(exm);
+                InstalledFontCollection ifc = new InstalledFontCollection();
+                Int64 isInstalled = 0;
+                foreach (FontFamily ff in ifc.Families)
+                {
+                    if (ff.Name == str)
+                    {
+                        isInstalled = 1;
+                        break;
+                    }
+                }
+                return (isInstalled);
+            }
+
+        }
+
+        private sealed class CheckdataMethod : FunctionMethod
+        {
+			public CheckdataMethod(string name, EraSaveFileType type)
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(Int64) };
+                CanRestructure = false;
+				this.name = name;
+				this.type = type;
+            }
+			string name;
+			EraSaveFileType type;
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 target = arguments[0].GetIntValue(exm);
+                if (target < 0)
+                    throw new CodeEE(name + "の引数に負の値(" + target + ")が指定されました");
+	            if (target > int.MaxValue)
+		            throw new CodeEE(name + "の引数(" + target + ")が大きすぎます");
+	            EraDataResult result = null;
+				result = exm.VEvaluator.CheckData((int)target, type);
+                exm.VEvaluator.RESULTS = result.DataMes;
+                return ((long)result.State);
+            }
+        }
+
+		/// <summary>
+		/// ファイル名をstringで指定する版・CHKVARDATAとCHKCHARADATAはこっちに分類
+		/// </summary>
+		private sealed class CheckdataStrMethod : FunctionMethod
+		{
+			public CheckdataStrMethod(string name, EraSaveFileType type)
+			{
+				ReturnType = typeof(Int64);
+				argumentTypeArray = new[] { typeof(string) };
+				CanRestructure = false;
+				this.name = name;
+				this.type = type;
+			}
+			string name;
+			EraSaveFileType type;
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				string datFilename = arguments[0].GetStrValue(exm);
+				EraDataResult result = null;
+				result = exm.VEvaluator.CheckData(datFilename, type);
+				exm.VEvaluator.RESULTS = result.DataMes;
+				return ((long)result.State);
+			}
+		}
+
+		/// <summary>
+		/// ファイル探索関数
+		/// </summary>
+		private sealed class FindFilesMethod : FunctionMethod
+		{
+			public FindFilesMethod(string name, EraSaveFileType type)
+			{
+				ReturnType = typeof(Int64);
+				argumentTypeArray = null;
+				CanRestructure = false;
+				this.name = name;
+				this.type = type;
+			}
+			string name;
+			EraSaveFileType type;
+
+			public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+			{
+				if (arguments.Length > 1)
+					return name + "関数の引数が多すぎます";
+				if (arguments.Length == 0 || arguments[0] == null)
+					return null;
+				if (!arguments[0].IsString)
+					return name + "関数の1番目の引数が文字列ではありません";
+				return null;
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				string pattern = "*";
+				if (arguments.Length > 0 && arguments[0] != null)
+					pattern = arguments[0].GetStrValue(exm);
+				List<string> filepathes = null;
+				filepathes = exm.VEvaluator.GetDatFiles(type == EraSaveFileType.CharVar, pattern);
+				string[] results = exm.VEvaluator.VariableData.DataStringArray[(int)(VariableCode.RESULTS & VariableCode.__LOWERCASE__)];
+				if (filepathes.Count <= results.Length)
+					filepathes.CopyTo(results);
+				else
+					filepathes.CopyTo(0, results, 0, results.Length);
+				return filepathes.Count;
+			}
+		}
+
+
+        private sealed class IsSkipMethod : FunctionMethod
+        {
+            public IsSkipMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new Type[] { };
+                CanRestructure = false;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                return exm.Process.SkipPrint ? 1L : 0L;
+            }
+        }
+
+		private sealed class MesSkipMethod : FunctionMethod
+		{
+			public MesSkipMethod(bool warn)
+			{
+				ReturnType = typeof(Int64);
+				argumentTypeArray = null;
+				CanRestructure = false;
+				this.warn = warn;
+			}
+			bool warn;
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                if (arguments.Length > 0)
+					return name + "関数の引数が多すぎます";
+				if (warn)
+					ParserMediator.Warn("関数MOUSESKIP()は推奨されません。代わりに関数MESSKIP()を使用してください", GlobalStatic.Process.GetScaningLine(), 1, false, false, null);
+                return null;
+            }
+			public override long GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				return GlobalStatic.Console.MesSkip ? 1L : 0L;
+			}
+		}
+
+
+        private sealed class GetColorMethod : FunctionMethod
+        {
+            public GetColorMethod(bool isDef)
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new Type[] { };
+                CanRestructure = isDef;
+                defaultColor = isDef;
+            }
+            bool defaultColor;
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Color color = (defaultColor) ? Config.ForeColor : GlobalStatic.Console.StringStyle.Color;
+                return (color.ToArgb() & 0xFFFFFF);
+            }
+        }
+
+        private sealed class GetFocusColorMethod : FunctionMethod
+        {
+            public GetFocusColorMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new Type[] { };
+                CanRestructure = true;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                return (Config.FocusColor.ToArgb() & 0xFFFFFF);
+            }
+        }
+
+        private sealed class GetBGColorMethod : FunctionMethod
+        {
+            public GetBGColorMethod(bool isDef)
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new Type[] { };
+                CanRestructure = isDef;
+                defaultColor = isDef;
+            }
+            bool defaultColor;
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Color color = (defaultColor) ? Config.BackColor : GlobalStatic.Console.bgColor;
+                return (color.ToArgb() & 0xFFFFFF);
+            }
+        }
+
+        private sealed class GetStyleMethod : FunctionMethod
+        {
+            public GetStyleMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new Type[] { };
+                CanRestructure = false;
+            }
+
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                FontStyle fontstyle = GlobalStatic.Console.StringStyle.FontStyle;
+                long ret = 0;
+                if ((fontstyle & FontStyle.Bold) == FontStyle.Bold)
+                    ret |= 1;
+                if ((fontstyle & FontStyle.Italic) == FontStyle.Italic)
+                    ret |= 2;
+                if ((fontstyle & FontStyle.Strikeout) == FontStyle.Strikeout)
+                    ret |= 4;
+                if ((fontstyle & FontStyle.Underline) == FontStyle.Underline)
+                    ret |= 8;
+                return (ret);
+            }
+        }
+
+        private sealed class GetFontMethod : FunctionMethod
+        {
+            public GetFontMethod()
+            {
+                ReturnType = typeof(string);
+                argumentTypeArray = new Type[] { };
+                CanRestructure = false;
+            }
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+            {
+                return (GlobalStatic.Console.StringStyle.Fontname);
+            }
+        }
+
+        private sealed class BarStringMethod : FunctionMethod
+        {
+            public BarStringMethod()
+            {
+                ReturnType = typeof(string);
+                argumentTypeArray = new[] { typeof(long), typeof(long), typeof(long) };
+                CanRestructure = true;
+            }
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+            {
+                long var = arguments[0].GetIntValue(exm);
+                long max = arguments[1].GetIntValue(exm);
+                long length = arguments[2].GetIntValue(exm);
+                return exm.CreateBar(var, max, length);
+            }
+        }
+
+        private sealed class CurrentAlignMethod : FunctionMethod
+        {
+            public CurrentAlignMethod()
+            {
+                ReturnType = typeof(string);
+                argumentTypeArray = new Type[] { };
+                CanRestructure = false;
+            }
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+            {
+	            if (exm.Console.Alignment == DisplayLineAlignment.LEFT)
+                    return "LEFT";
+	            if (exm.Console.Alignment == DisplayLineAlignment.CENTER)
+		            return "CENTER";
+	            return "RIGHT";
+            }
+        }
+
+        private sealed class CurrentRedrawMethod : FunctionMethod
+        {
+            public CurrentRedrawMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new Type[] { };
+                CanRestructure = false;
+            }
+            public override long GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                return (exm.Console.Redraw == ConsoleRedraw.None) ? 0L : 1L;
+            }
+        }
+
+		private sealed class ColorFromNameMethod : FunctionMethod
+		{
+			public ColorFromNameMethod()
+			{
+				ReturnType = typeof(Int64);
+				argumentTypeArray = new[] { typeof(string) };
+				CanRestructure = true;
+			}
+			public override long GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				string colorName = arguments[0].GetStrValue(exm);
+				Color color = Color.FromName(colorName);
+				int i = 0;
+				if (color.A > 0)
+					i = (color.R << 16) + (color.G << 8) + color.B;
+				else
+				{
+					if (colorName.Equals("transparent", StringComparison.OrdinalIgnoreCase))
+						throw new CodeEE("無色透明(Transparent)は色として指定できません");
+					//throw new CodeEE("指定された色名\"" + colorName + "\"は無効な色名です");
+					i = -1;
+				}
+				return i;
+			}
+		}
+
+		private sealed class ColorFromRGBMethod : FunctionMethod
+		{
+			public ColorFromRGBMethod()
+			{
+				ReturnType = typeof(Int64);
+				argumentTypeArray = new[] { typeof(long), typeof(long), typeof(long) };
+				CanRestructure = true;
+			}
+			public override long GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				long r = arguments[0].GetIntValue(exm);
+				if(r < 0 || r > 255)
+					throw new CodeEE("第1引数が0から255の範囲外です");
+				long g = arguments[1].GetIntValue(exm);
+				if(g< 0 || g > 255)
+					throw new CodeEE("第2引数が0から255の範囲外です");
+				long b = arguments[2].GetIntValue(exm);
+				if(b < 0 || b > 255)
+					throw new CodeEE("第3引数が0から255の範囲外です");
+				return (r << 16) + (g << 8) + b;
+			}
+		}
+		/// <summary>
+		/// 1810 作ったけど保留
+		/// </summary>
+		private sealed class GetRefMethod : FunctionMethod
+		{
+			public GetRefMethod()
+			{
+				ReturnType = typeof(string);
+				argumentTypeArray = null;
+				CanRestructure = false;
+			}
+			public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+			{
+				if (arguments.Length < 1)
+					return name + "関数には少なくとも1つの引数が必要です";
+				if (arguments.Length > 1)
+					return name + "関数の引数が多すぎます";
+				if (arguments[0] == null)
+					return name + "関数の1番目の引数は省略できません";
+				if (!(arguments[0] is UserDefinedRefMethodNoArgTerm))
+					return name + "関数の1番目の引数が関数参照ではありません";
+				return null;
+			}
+			public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+			{
+				return ((UserDefinedRefMethodNoArgTerm)arguments[0]).GetRefName();
+			}
+		}
+        #endregion
+
+        #region 定数取得
+        private sealed class MoneyStrMethod : FunctionMethod
+        {
+            public MoneyStrMethod()
+            {
+                ReturnType = typeof(string);
+                argumentTypeArray = null;
+                CanRestructure = true;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                //通常2つ、1つ省略可能で1~2の引数が必要。
+                if (arguments.Length < 1)
+                    return name + "関数には少なくとも1つの引数が必要です";
+                if (arguments.Length > 2)
+                    return name + "関数の引数が多すぎます";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (arguments[0].GetOperandType() != typeof(Int64))
+                    return name + "関数の1番目の引数の型が正しくありません";
+                if ((arguments.Length >= 2) && (arguments[1] != null) && (arguments[1].GetOperandType() != typeof(string)))
+                    return name + "関数の2番目の引数の型が正しくありません";
+                return null;
+            }
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+            {
+                long money = arguments[0].GetIntValue(exm);
+                if ((arguments.Length < 2) || (arguments[1] == null))
+                    return (Config.MoneyFirst) ? Config.MoneyLabel + money : money + Config.MoneyLabel;
+                string format = arguments[1].GetStrValue(exm);
+                string ret;
+                try
+                {
+                    ret = money.ToString(format);
+                }
+                catch (FormatException)
+                {
+                    throw new CodeEE("MONEYSTR関数の第2引数の書式指定が間違っています");
+                }
+                return (Config.MoneyFirst) ? Config.MoneyLabel + ret : ret + Config.MoneyLabel;
+            }
+        }
+
+        private sealed class GetPrintCPerLineMethod : FunctionMethod
+        {
+            public GetPrintCPerLineMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new Type[] { };
+                CanRestructure = true;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                return (Config.PrintCPerLine);
+            }
+        }
+
+        private sealed class PrintCLengthMethod : FunctionMethod
+        {
+            public PrintCLengthMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new Type[] { };
+                CanRestructure = true;
+            }
+            public override long GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                return (Config.PrintCLength);
+            }
+        }
+
+        private sealed class GetSaveNosMethod : FunctionMethod
+        {
+            public GetSaveNosMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new Type[] { };
+                CanRestructure = true;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                return (Config.SaveDataNos);
+            }
+        }
+
+        private sealed class GettimeMethod : FunctionMethod
+        {
+            public GettimeMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new Type[] { };
+                CanRestructure = false;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                long date = DateTime.Now.Year;
+                date = date * 100 + DateTime.Now.Month;
+                date = date * 100 + DateTime.Now.Day;
+                date = date * 100 + DateTime.Now.Hour;
+                date = date * 100 + DateTime.Now.Minute;
+                date = date * 100 + DateTime.Now.Second;
+                date = date * 1000 + DateTime.Now.Millisecond;
+                return (date);//17桁。2京くらい。
+            }
+        }
+
+        private sealed class GettimesMethod : FunctionMethod
+        {
+            public GettimesMethod()
+            {
+                ReturnType = typeof(string);
+                argumentTypeArray = new Type[] { };
+                CanRestructure = false;
+            }
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+            {
+                return (DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"));
+            }
+        }
+
+        private sealed class GetmsMethod : FunctionMethod
+        {
+            public GetmsMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new Type[] { };
+                CanRestructure = false;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                //西暦0001年1月1日からの経過時間をミリ秒で。
+                //Ticksは100ナノ秒単位であるが実際にはそんな精度はないので無駄。
+                return (DateTime.Now.Ticks / 10000);
+            }
+        }
+
+        private sealed class GetSecondMethod : FunctionMethod
+        {
+            public GetSecondMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new Type[] { };
+                CanRestructure = false;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                //西暦0001年1月1日からの経過時間を秒で。
+                //Ticksは100ナノ秒単位であるが実際にはそんな精度はないので無駄。
+                return (DateTime.Now.Ticks / 10000000);
+            }
+        }
+        #endregion
+
+        #region 数学関数
+        private sealed class RandMethod : FunctionMethod
+        {
+            public RandMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                CanRestructure = false;
+            }
+
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                //通常2つ、1つ省略可能で1~2の引数が必要。
+                if (arguments.Length < 1)
+                    return name + "関数には少なくとも1つの引数が必要です";
+                if (arguments.Length > 2)
+                    return name + "関数の引数が多すぎます";
+                if (arguments.Length == 1)
+                {
+                    if (arguments[0] == null)
+                        return name + "関数には少なくとも1つの引数が必要です";
+                    if ((arguments[0].GetOperandType() != typeof(Int64)))
+                        return name + "関数の1番目の引数の型が正しくありません";
+                    return null;
+                }
+                //1番目は省略可能
+                if ((arguments[0] != null) && (arguments[0].GetOperandType() != typeof(Int64)))
+                    return name + "関数の1番目の引数の型が正しくありません";
+                if ((arguments[1] != null) && (arguments[1].GetOperandType() != typeof(Int64)))
+                    return name + "関数の2番目の引数の型が正しくありません";
+                return null;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 max = 0;
+                Int64 min = 0;
+                if (arguments.Length == 1)
+                    max = arguments[0].GetIntValue(exm);
+                else
+                {
+                    if (arguments[0] != null)
+                        min = arguments[0].GetIntValue(exm);
+                    max = arguments[1].GetIntValue(exm);
+                }
+                if (max <= min)
+                {
+	                if (min == 0)
+                        throw new CodeEE("RANDの最大値に0以下の値(" + max + ")が指定されました");
+	                throw new CodeEE("RANDの最大値に最小値以下の値(" + max + ")が指定されました");
+                }
+                return (exm.VEvaluator.GetNextRand(max - min) + min);
+            }
+        }
+
+        private sealed class MaxMethod : FunctionMethod
+        {
+            bool isMax;
+            public MaxMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                isMax = true;
+                CanRestructure = true;
+            }
+            public MaxMethod(bool max)
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                isMax = max;
+                CanRestructure = true;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                if (arguments.Length < 1)
+                    return name + "関数には少なくとも1つの引数が必要です";
+                for (int i = 0; i < arguments.Length; i++)
+                {
+                    if (arguments[i] == null)
+                        return name + "関数の" + (i + 1) + "番目の引数は省略できません";
+                    if (arguments[i].GetOperandType() != typeof(Int64))
+                        return name + "関数の" + (i + 1) + "番目の引数の型が正しくありません";
+                }
+                return null;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 ret = arguments[0].GetIntValue(exm);
+
+                for (int i = 1; i < arguments.Length; i++)
+                {
+                    Int64 newRet = arguments[i].GetIntValue(exm);
+                    if (isMax)
+                    {
+                        if (ret < newRet)
+                            ret = newRet;
+                    }
+                    else
+                    {
+                        if (ret > newRet)
+                            ret = newRet;
+                    }
+                }
+                return (ret);
+            }
+        }
+
+        private sealed class AbsMethod : FunctionMethod
+        {
+            public AbsMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(Int64) };
+                CanRestructure = true;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 ret = arguments[0].GetIntValue(exm);
+                return (Math.Abs(ret));
+            }
+        }
+
+        private sealed class PowerMethod : FunctionMethod
+        {
+            public PowerMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(Int64), typeof(Int64) };
+                CanRestructure = true;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 x = arguments[0].GetIntValue(exm);
+                Int64 y = arguments[1].GetIntValue(exm);
+                double pow = Math.Pow(x, y);
+                if (double.IsNaN(pow))
+                    throw new CodeEE("累乗結果が非数値です");
+	            if (double.IsInfinity(pow))
+		            throw new CodeEE("累乗結果が無限大です");
+	            if ((pow >= Int64.MaxValue) || (pow <= Int64.MinValue))
+		            throw new CodeEE("累乗結果(" + pow + ")が64ビット符号付き整数の範囲外です");
+	            return ((long)pow);
+            }
+        }
+
+        private sealed class SqrtMethod : FunctionMethod
+        {
+            public SqrtMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(Int64) };
+                CanRestructure = true;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 ret = arguments[0].GetIntValue(exm);
+                if (ret < 0)
+                    throw new CodeEE("SQRT関数の引数に負の値が指定されました");
+                return ((Int64)Math.Sqrt(ret));
+            }
+        }
+
+        private sealed class CbrtMethod : FunctionMethod
+        {
+            public CbrtMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(Int64) };
+                CanRestructure = true;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 ret = arguments[0].GetIntValue(exm);
+                if (ret < 0)
+                    throw new CodeEE("CBRT関数の引数に負の値が指定されました");
+                return ((Int64)Math.Pow(ret, 1.0 / 3.0));
+            }
+        }
+
+        private sealed class LogMethod : FunctionMethod
+        {
+            double Base;
+            public LogMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(Int64) };
+                Base = Math.E;
+                CanRestructure = true;
+            }
+            public LogMethod(double b)
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(Int64) };
+                Base = b;
+                CanRestructure = true;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 ret = arguments[0].GetIntValue(exm);
+                if (ret <= 0)
+                    throw new CodeEE("対数関数の引数に0以下の値が指定されました");
+                if (Base <= 0.0d)
+                    throw new CodeEE("対数関数の底に0以下の値が指定されました");
+                double dret = ret;
+                if (Base == Math.E)
+                    dret = Math.Log(dret);
+                else
+                    dret = Math.Log10(dret);
+                if (double.IsNaN(dret))
+                    throw new CodeEE("計算値が非数値です");
+	            if (double.IsInfinity(dret))
+		            throw new CodeEE("計算値が無限大です");
+	            if ((dret >= Int64.MaxValue) || (dret <= Int64.MinValue))
+		            throw new CodeEE("計算結果(" + dret + ")が64ビット符号付き整数の範囲外です");
+	            return ((Int64)dret);
+            }
+        }
+
+        private sealed class ExpMethod : FunctionMethod
+        {
+            public ExpMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(Int64) };
+                CanRestructure = true;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 ret = arguments[0].GetIntValue(exm);
+                double dret = Math.Exp(ret);
+                if (double.IsNaN(dret))
+                    throw new CodeEE("計算値が非数値です");
+	            if (double.IsInfinity(dret))
+		            throw new CodeEE("計算値が無限大です");
+	            if ((dret >= Int64.MaxValue) || (dret <= Int64.MinValue))
+		            throw new CodeEE("計算結果(" + dret + ")が64ビット符号付き整数の範囲外です");
+
+	            return ((Int64)dret);
+            }
+        }
+
+        private sealed class SignMethod : FunctionMethod
+        {
+
+            public SignMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(Int64) };
+                CanRestructure = true;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 ret = arguments[0].GetIntValue(exm);
+                return (Math.Sign(ret));
+            }
+        }
+
+        private sealed class GetLimitMethod : FunctionMethod
+        {
+            public GetLimitMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(Int64), typeof(Int64), typeof(Int64) };
+                CanRestructure = true;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 value = arguments[0].GetIntValue(exm);
+                Int64 min = arguments[1].GetIntValue(exm);
+                Int64 max = arguments[2].GetIntValue(exm);
+                Int64 ret = 0;
+                if (value < min)
+                    ret = min;
+                else if (value > max)
+                    ret = max;
+                else
+                    ret = value;
+                return (ret);
+            }
+        }
+        #endregion
+
+        #region 変数操作系
+        private sealed class SumArrayMethod : FunctionMethod
+        {
+            bool isCharaRange;
+            public SumArrayMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                isCharaRange = false;
+                CanRestructure = false;
+            }
+            public SumArrayMethod(bool isChara)
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                isCharaRange = isChara;
+                CanRestructure = false;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                if (arguments.Length < 1)
+                    return name + "関数には少なくとも1つの引数が必要です";
+                if (arguments.Length > 3)
+                    return name + "関数の引数が多すぎます";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (!(arguments[0] is VariableTerm))
+                    return name + "関数の1番目の引数が変数ではありません";
+                VariableTerm varToken = (VariableTerm)arguments[0];
+                if (varToken.IsString)
+                    return name + "関数の1番目の引数が数値変数ではありません";
+                if (isCharaRange && !varToken.Identifier.IsCharacterData)
+                    return name + "関数の1番目の引数がキャラクタ変数ではありません";
+                if (!isCharaRange && !varToken.Identifier.IsArray1D && !varToken.Identifier.IsArray2D && !varToken.Identifier.IsArray3D)
+                    return name + "関数の1番目の引数が配列変数ではありません";
+                if (arguments.Length == 1)
+                    return null;
+                if ((arguments[1] != null) && (arguments[1].GetOperandType() != typeof(Int64)))
+                    return name + "関数の2番目の変数が数値ではありません";
+                if (arguments.Length == 2)
+                    return null;
+                if ((arguments[2] != null) && (arguments[2].GetOperandType() != typeof(Int64)))
+                    return name + "関数の3番目の変数が数値ではありません";
+                return null;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                VariableTerm varTerm = (VariableTerm)arguments[0];
+                Int64 index1 = (arguments.Length >= 2 && arguments[1] != null) ? arguments[1].GetIntValue(exm) : 0;
+                Int64 index2 = (arguments.Length == 3 && arguments[2] != null) ? arguments[2].GetIntValue(exm) : (isCharaRange ? exm.VEvaluator.CHARANUM : varTerm.GetLastLength());
+
+                FixedVariableTerm p = varTerm.GetFixedVariableTerm(exm);
+                if (!isCharaRange)
+                {
+                    p.IsArrayRangeValid(index1, index2, "SUMARRAY", 2L, 3L);
+                    return (exm.VEvaluator.GetArraySum(p, index1, index2));
+                }
+
+	            Int64 charaNum = exm.VEvaluator.CHARANUM;
+	            if (index1 >= charaNum || index1 < 0 || index2 > charaNum || index2 < 0)
+		            throw new CodeEE("SUMCARRAY関数の範囲指定がキャラクタ配列の範囲を超えています(" + index1 + "~" + index2 + ")");
+	            return (exm.VEvaluator.GetArraySumChara(p, index1, index2));
+            }
+        }
+
+        private sealed class MatchMethod : FunctionMethod
+        {
+            bool isCharaRange;
+            public MatchMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                isCharaRange = false;
+                CanRestructure = false;
+                HasUniqueRestructure = true;
+            }
+            public MatchMethod(bool isChara)
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                isCharaRange = isChara;
+                CanRestructure = false;
+                HasUniqueRestructure = true;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                if (arguments.Length < 2)
+                    return name + "関数には少なくとも2つの引数が必要です";
+                if (arguments.Length > 4)
+                    return name + "関数の引数が多すぎます";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (!(arguments[0] is VariableTerm))
+                    return name + "関数の1番目の引数が変数ではありません";
+                VariableTerm varToken = (VariableTerm)arguments[0];
+                if (isCharaRange && !varToken.Identifier.IsCharacterData)
+                    return name + "関数の1番目の引数がキャラクタ変数ではありません";
+                if (!isCharaRange && (varToken.Identifier.IsArray2D || varToken.Identifier.IsArray3D))
+                    return name + "関数は二重配列・三重配列には対応していません";
+                if (!isCharaRange && !varToken.Identifier.IsArray1D)
+                    return name + "関数の1番目の引数が配列変数ではありません";
+                if (arguments[1] == null)
+                    return name + "関数の2番目の引数は省略できません";
+                if (arguments[1].GetOperandType() != arguments[0].GetOperandType())
+                    return name + "関数の1番目の引数と2番目の引数の型が異なります";
+                if ((arguments.Length >= 3) && (arguments[2] != null) && (arguments[2].GetOperandType() != typeof(Int64)))
+                    return name + "関数の3番目の引数の型が正しくありません";
+                if ((arguments.Length >= 4) && (arguments[3] != null) && (arguments[3].GetOperandType() != typeof(Int64)))
+                    return name + "関数の4番目の引数の型が正しくありません";
+                return null;
+            }
+
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                VariableTerm varTerm = arguments[0] as VariableTerm;
+                Int64 start = (arguments.Length > 2 && arguments[2] != null) ? arguments[2].GetIntValue(exm) : 0;
+                Int64 end = (arguments.Length > 3 && arguments[3] != null) ? arguments[3].GetIntValue(exm) : (isCharaRange ? exm.VEvaluator.CHARANUM : varTerm.GetLength());
+
+                FixedVariableTerm p = varTerm.GetFixedVariableTerm(exm);
+                if (!isCharaRange)
+                {
+                    p.IsArrayRangeValid(start, end, "MATCH", 3L, 4L);
+                    if (arguments[0].GetOperandType() == typeof(Int64))
+                    {
+                        Int64 targetValue = arguments[1].GetIntValue(exm);
+                        return (exm.VEvaluator.GetMatch(p, targetValue, start, end));
+                    }
+
+	                string targetStr = arguments[1].GetStrValue(exm);
+	                return (exm.VEvaluator.GetMatch(p, targetStr, start, end));
+                }
+
+	            Int64 charaNum = exm.VEvaluator.CHARANUM;
+	            if (start >= charaNum || start < 0 || end > charaNum || end < 0)
+		            throw new CodeEE("CMATCH関数の範囲指定がキャラクタ配列の範囲を超えています(" + start + "~" + end + ")");
+	            if (arguments[0].GetOperandType() == typeof(Int64))
+	            {
+		            Int64 targetValue = arguments[1].GetIntValue(exm);
+		            return (exm.VEvaluator.GetMatchChara(p, targetValue, start, end));
+	            }
+
+	            {
+		            string targetStr = arguments[1].GetStrValue(exm);
+		            return (exm.VEvaluator.GetMatchChara(p, targetStr, start, end));
+	            }
+            }
+
+            public override bool UniqueRestructure(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                arguments[0].Restructure(exm);
+                for (int i = 1; i < arguments.Length; i++)
+                {
+                    if (arguments[i] == null)
+                        continue;
+                    arguments[i] = arguments[i].Restructure(exm);
+                }
+                return false;
+            }
+        }
+
+        private sealed class GroupMatchMethod : FunctionMethod
+        {
+            public GroupMatchMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                CanRestructure = false;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                if (arguments.Length < 2)
+                    return name + "関数には少なくとも2つの引数が必要です";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                Type baseType = arguments[0].GetOperandType();
+                for (int i = 1; i < arguments.Length; i++)
+                {
+                    if (arguments[i] == null)
+                        return name + "関数の" + (i + 1) + "番目の引数は省略できません";
+                    if (arguments[i].GetOperandType() != baseType)
+                        return name + "関数の" + (i + 1) + "番目の引数の型が正しくありません";
+                }
+                return null;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 ret = 0;
+                if (arguments[0].GetOperandType() == typeof(Int64))
+                {
+                    Int64 baseValue = arguments[0].GetIntValue(exm);
+                    for (int i = 1; i < arguments.Length; i++)
+                    {
+                        if (baseValue == arguments[i].GetIntValue(exm))
+                            ret += 1;
+                    }
+                }
+                else
+                {
+                    string baseString = arguments[0].GetStrValue(exm);
+                    for (int i = 1; i < arguments.Length; i++)
+                    {
+                        if (baseString == arguments[i].GetStrValue(exm))
+                            ret += 1;
+                    }
+                }
+                return (ret);
+            }
+        }
+
+        private sealed class NosamesMethod : FunctionMethod
+        {
+            public NosamesMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                CanRestructure = false;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                if (arguments.Length < 2)
+                    return name + "関数には少なくとも2つの引数が必要です";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                Type baseType = arguments[0].GetOperandType();
+                for (int i = 1; i < arguments.Length; i++)
+                {
+                    if (arguments[i] == null)
+                        return name + "関数の" + (i + 1) + "番目の引数は省略できません";
+                    if (arguments[i].GetOperandType() != baseType)
+                        return name + "関数の" + (i + 1) + "番目の引数の型が正しくありません";
+                }
+                return null;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                if (arguments[0].GetOperandType() == typeof(Int64))
+                {
+                    Int64 baseValue = arguments[0].GetIntValue(exm);
+                    for (int i = 1; i < arguments.Length; i++)
+                    {
+                        if (baseValue == arguments[i].GetIntValue(exm))
+                            return 0L;
+                    }
+                }
+                else
+                {
+                    string baseValue = arguments[0].GetStrValue(exm);
+                    for (int i = 1; i < arguments.Length; i++)
+                    {
+                        if (baseValue == arguments[i].GetStrValue(exm))
+                            return 0L;
+                    }
+                }
+                return 1L;
+            }
+        }
+
+        private sealed class AllsamesMethod : FunctionMethod
+        {
+            public AllsamesMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                CanRestructure = false;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                if (arguments.Length < 2)
+                    return name + "関数には少なくとも2つの引数が必要です";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                Type baseType = arguments[0].GetOperandType();
+                for (int i = 1; i < arguments.Length; i++)
+                {
+                    if (arguments[i] == null)
+                        return name + "関数の" + (i + 1) + "番目の引数は省略できません";
+                    if (arguments[i].GetOperandType() != baseType)
+                        return name + "関数の" + (i + 1) + "番目の引数の型が正しくありません";
+                }
+                return null;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                if (arguments[0].GetOperandType() == typeof(Int64))
+                {
+                    Int64 baseValue = arguments[0].GetIntValue(exm);
+                    for (int i = 1; i < arguments.Length; i++)
+                    {
+                        if (baseValue != arguments[i].GetIntValue(exm))
+                            return 0L;
+                    }
+                }
+                else
+                {
+                    string baseValue = arguments[0].GetStrValue(exm);
+                    for (int i = 1; i < arguments.Length; i++)
+                    {
+                        if (baseValue != arguments[i].GetStrValue(exm))
+                            return 0L;
+                    }
+                }
+                return 1L;
+            }
+        }
+
+        private sealed class MaxArrayMethod : FunctionMethod
+        {
+            bool isCharaRange;
+            bool isMax;
+            string funcName;
+            public MaxArrayMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                isCharaRange = false;
+                isMax = true;
+                funcName = "MAXARRAY";
+                CanRestructure = false;
+            }
+            public MaxArrayMethod(bool isChara)
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                isCharaRange = isChara;
+                isMax = true;
+                if (isCharaRange)
+                    funcName = "MAXCARRAY";
+                else
+                    funcName = "MAXARRAY";
+                CanRestructure = false;
+            }
+            public MaxArrayMethod(bool isChara, bool isMaxFunc)
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                isCharaRange = isChara;
+                isMax = isMaxFunc;
+                funcName = (isMax ? "MAX" : "MIN") + (isCharaRange ? "C" : "") + "ARRAY";
+                CanRestructure = false;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                if (arguments.Length < 1)
+                    return name + "関数には少なくとも1つの引数が必要です";
+                if (arguments.Length > 3)
+                    return name + "関数の引数が多すぎます";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (!(arguments[0] is VariableTerm))
+                    return name + "関数の1番目の引数が変数ではありません";
+                VariableTerm varToken = (VariableTerm)arguments[0];
+                if (isCharaRange && !varToken.Identifier.IsCharacterData)
+                    return name + "関数の1番目の引数がキャラクタ変数ではありません";
+                if (!varToken.IsInteger)
+                    return name + "関数の1番目の引数が数値変数ではありません";
+                if (!isCharaRange && (varToken.Identifier.IsArray2D || varToken.Identifier.IsArray3D))
+                    return name + "関数は二重配列・三重配列には対応していません";
+                if (!varToken.Identifier.IsArray1D)
+                    return name + "関数の1番目の引数が配列変数ではありません";
+                if ((arguments.Length >= 2) && (arguments[1] != null) && (arguments[1].GetOperandType() != typeof(Int64)))
+                    return name + "関数の2番目の引数の型が正しくありません";
+                if ((arguments.Length >= 3) && (arguments[2] != null) && (arguments[2].GetOperandType() != typeof(Int64)))
+                    return name + "関数の3番目の引数の型が正しくありません";
+                return null;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                VariableTerm vTerm = (VariableTerm)arguments[0];
+                Int64 start = (arguments.Length > 1 && arguments[1] != null) ? arguments[1].GetIntValue(exm) : 0;
+                Int64 end = (arguments.Length > 2 && arguments[2] != null) ? end = arguments[2].GetIntValue(exm) : (isCharaRange ? exm.VEvaluator.CHARANUM : vTerm.GetLength());
+                FixedVariableTerm p = vTerm.GetFixedVariableTerm(exm);
+                if (!isCharaRange)
+                {
+                    p.IsArrayRangeValid(start, end, funcName, 2L, 3L);
+                    return (exm.VEvaluator.GetMaxArray(p, start, end, isMax));
+                }
+
+	            Int64 charaNum = exm.VEvaluator.CHARANUM;
+	            if (start >= charaNum || start < 0 || end > charaNum || end < 0)
+		            throw new CodeEE(funcName + "関数の範囲指定がキャラクタ配列の範囲を超えています(" + start + "~" + end + ")");
+	            return (exm.VEvaluator.GetMaxArrayChara(p, start, end, isMax));
+            }
+        }
+
+        private sealed class GetbitMethod : FunctionMethod
+        {
+            public GetbitMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(Int64), typeof(Int64) };
+                CanRestructure = true;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                string ret = base.CheckArgumentType(name, arguments);
+                if (ret != null)
+                    return ret;
+                if (arguments[1] is SingleTerm)
+                {
+                    Int64 m = ((SingleTerm)arguments[1]).Int;
+                    if (m < 0 || m > 63)
+                        return "GETBIT関数の第2引数(" + m + ")が範囲(0~63)を超えています";
+                }
+                return null;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 n = arguments[0].GetIntValue(exm);
+                Int64 m = arguments[1].GetIntValue(exm);
+                if ((m < 0) || (m > 63))
+                    throw new CodeEE("GETBIT関数の第2引数(" + m + ")が範囲(0~63)を超えています");
+                int mi = (int)m;
+                return ((n >> mi) & 1);
+            }
+        }
+
+        private sealed class GetnumMethod : FunctionMethod
+        {
+            public GetnumMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                CanRestructure = true;
+                HasUniqueRestructure = true;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                if (arguments.Length != 2)
+                    return name + "関数には2つの引数が必要です";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (!(arguments[0] is VariableTerm))
+                    return name + "関数の1番目の引数の型が正しくありません";
+                if (arguments[1] == null)
+                    return name + "関数の2番目の引数は省略できません";
+                if (arguments[1].GetOperandType() != typeof(string))
+                    return name + "関数の2番目の引数の型が正しくありません";
+                return null;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                VariableTerm vToken = (VariableTerm)arguments[0];
+                VariableCode varCode = vToken.Identifier.Code;
+                string key = arguments[1].GetStrValue(exm);
+                int ret = 0;
+                if (exm.VEvaluator.Constant.TryKeywordToInteger(out ret, varCode, key, -1))
+                    return ret;
+	            return -1;
+            }
+            public override bool UniqueRestructure(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                arguments[1] = arguments[1].Restructure(exm);
+                return arguments[1] is SingleTerm;
+            }
+        }
+
+        private sealed class GetPalamLVMethod : FunctionMethod
+        {
+            public GetPalamLVMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(Int64), typeof(Int64) };
+                CanRestructure = false;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                string errStr = base.CheckArgumentType(name, arguments);
+                if (errStr != null)
+                    return errStr;
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                return null;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 value = arguments[0].GetIntValue(exm);
+                Int64 maxLv = arguments[1].GetIntValue(exm);
+
+                return (exm.VEvaluator.getPalamLv(value, maxLv));
+            }
+        }
+
+        private sealed class GetExpLVMethod : FunctionMethod
+        {
+            public GetExpLVMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(Int64), typeof(Int64) };
+                CanRestructure = false;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                string errStr = base.CheckArgumentType(name, arguments);
+                if (errStr != null)
+                    return errStr;
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                return null;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 value = arguments[0].GetIntValue(exm);
+                Int64 maxLv = arguments[1].GetIntValue(exm);
+
+                return (exm.VEvaluator.getExpLv(value, maxLv));
+            }
+        }
+
+        private sealed class FindElementMethod : FunctionMethod
+        {
+            public FindElementMethod(bool last)
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                CanRestructure = true; //すべて定数項ならできるはず
+                HasUniqueRestructure = true;
+                isLast = last;
+                funcName = isLast ? "FINDLASTELEMENT" : "FINDELEMENT";
+            }
+            bool isLast;
+            string funcName;
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                if (arguments.Length < 2)
+                    return name + "関数には少なくとも2つの引数が必要です";
+                if (arguments.Length > 5)
+                    return name + "関数の引数が多すぎます";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                VariableTerm varToken = arguments[0] as VariableTerm;
+                if (varToken == null)
+                    return name + "関数の1番目の引数が変数ではありません";
+                if (varToken.Identifier.IsArray2D || varToken.Identifier.IsArray3D)
+                    return name + "関数は二重配列・三重配列には対応していません";
+                if (!varToken.Identifier.IsArray1D)
+                    return name + "関数の1番目の引数が配列変数ではありません";
+                Type baseType = arguments[0].GetOperandType();
+                if (arguments[1] == null)
+                    return name + "関数の2番目の引数は省略できません";
+                if (arguments[1].GetOperandType() != baseType)
+                    return name + "関数の2番目の引数の型が正しくありません";
+                if ((arguments.Length >= 3) && (arguments[2] != null) && (arguments[2].GetOperandType() != typeof(Int64)))
+                    return name + "関数の3番目の引数の型が正しくありません";
+                if ((arguments.Length >= 4) && (arguments[3] != null) && (arguments[3].GetOperandType() != typeof(Int64)))
+                    return name + "関数の4番目の引数の型が正しくありません";
+                if ((arguments.Length >= 5) && (arguments[4] != null) && (arguments[4].GetOperandType() != typeof(Int64)))
+                    return name + "関数の5番目の引数の型が正しくありません";
+                return null;
+            }
+
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                bool isExact = false;
+                VariableTerm varTerm = (VariableTerm)arguments[0];
+
+                Int64 start = (arguments.Length > 2 && arguments[2] != null) ? arguments[2].GetIntValue(exm) : 0;
+                Int64 end = (arguments.Length > 3 && arguments[3] != null) ? arguments[3].GetIntValue(exm) : varTerm.GetLength();
+                if (arguments.Length > 4 && arguments[4] != null)
+                    isExact = (arguments[4].GetIntValue(exm) != 0);
+
+                FixedVariableTerm p = varTerm.GetFixedVariableTerm(exm);
+                p.IsArrayRangeValid(start, end, funcName, 3L, 4L);
+
+                if (arguments[0].GetOperandType() == typeof(Int64))
+                {
+                    Int64 targetValue = arguments[1].GetIntValue(exm);
+                    return exm.VEvaluator.FindElement(p, targetValue, start, end, isExact, isLast);
+                }
+
+	            Regex targetString = null;
+	            try
+	            {
+		            targetString = new Regex(arguments[1].GetStrValue(exm));
+	            }
+	            catch (ArgumentException)
+	            {
+		            throw new CodeEE("第2引数が正規表現として不正です");
+	            }
+	            return exm.VEvaluator.FindElement(p, targetString, start, end, isExact, isLast);
+            }
+
+
+            public override bool UniqueRestructure(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                bool isConst = true;
+
+                arguments[0].Restructure(exm);
+                VariableTerm varToken = arguments[0] as VariableTerm;
+                isConst = varToken.Identifier.IsConst;
+
+                for (int i = 1; i < arguments.Length; i++)
+                {
+                    if (arguments[i] == null)
+                        continue;
+                    arguments[i] = arguments[i].Restructure(exm);
+                    if (isConst && !(arguments[i] is SingleTerm))
+                        isConst = false;
+                }
+                return isConst;
+            }
+        }
+
+        private sealed class InRangeMethod : FunctionMethod
+        {
+            public InRangeMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(Int64), typeof(Int64), typeof(Int64) };
+                CanRestructure = true;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 value = arguments[0].GetIntValue(exm);
+                Int64 min = arguments[1].GetIntValue(exm);
+                Int64 max = arguments[2].GetIntValue(exm);
+                return ((value >= min) && (value <= max)) ? 1L : 0L;
+            }
+        }
+
+        private sealed class InRangeArrayMethod : FunctionMethod
+        {
+            public InRangeArrayMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                CanRestructure = false;
+            }
+            public InRangeArrayMethod(bool isChara)
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                isCharaRange = isChara;
+                CanRestructure = false;
+            }
+            private bool isCharaRange;
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                if (arguments.Length < 2)
+                    return name + "関数には少なくとも2つの引数が必要です";
+                if (arguments.Length > 6)
+                    return name + "関数の引数が多すぎます";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (!(arguments[0] is VariableTerm))
+                    return name + "関数の1番目の引数が変数ではありません";
+                VariableTerm varToken = (VariableTerm)arguments[0];
+                if (isCharaRange && !varToken.Identifier.IsCharacterData)
+                    return name + "関数の1番目の引数がキャラクタ変数ではありません";
+                if (!isCharaRange && (varToken.Identifier.IsArray2D || varToken.Identifier.IsArray3D))
+                    return name + "関数は二重配列・三重配列には対応していません";
+                if (!isCharaRange && !varToken.Identifier.IsArray1D)
+                    return name + "関数の1番目の引数が配列変数ではありません";
+                if (!varToken.IsInteger)
+                    return name + "関数の1番目の引数が数値型変数ではありません";
+                if (arguments[1] == null)
+                    return name + "関数の2番目の引数は省略できません";
+                if (arguments[1].GetOperandType() != typeof(Int64))
+                    return name + "関数の2番目の引数が数値型ではありません";
+                if (arguments[2] == null)
+                    return name + "関数の3番目の引数は省略できません";
+                if (arguments[2].GetOperandType() != typeof(Int64))
+                    return name + "関数の3番目の引数が数値型ではありません";
+                if ((arguments.Length >= 4) && (arguments[3] != null) && (arguments[3].GetOperandType() != typeof(Int64)))
+                    return name + "関数の4番目の引数の型が正しくありません";
+                if ((arguments.Length >= 5) && (arguments[4] != null) && (arguments[4].GetOperandType() != typeof(Int64)))
+                    return name + "関数の5番目の引数の型が正しくありません";
+                return null;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Int64 min = arguments[1].GetIntValue(exm);
+                Int64 max = arguments[2].GetIntValue(exm);
+
+                VariableTerm varTerm = arguments[0] as VariableTerm;
+                Int64 start = (arguments.Length > 3 && arguments[3] != null) ? arguments[3].GetIntValue(exm) : 0;
+                Int64 end = (arguments.Length > 4 && arguments[4] != null) ? arguments[4].GetIntValue(exm) : (isCharaRange ? exm.VEvaluator.CHARANUM : varTerm.GetLength());
+
+                FixedVariableTerm p = varTerm.GetFixedVariableTerm(exm);
+
+                if (!isCharaRange)
+                {
+                    p.IsArrayRangeValid(start, end, "INRANGEARRAY", 4L, 5L);
+                    return (exm.VEvaluator.GetInRangeArray(p, min, max, start, end));
+                }
+
+	            Int64 charaNum = exm.VEvaluator.CHARANUM;
+	            if (start >= charaNum || start < 0 || end > charaNum || end < 0)
+		            throw new CodeEE("INRANGECARRAY関数の範囲指定がキャラクタ配列の範囲を超えています(" + start + "~" + end + ")");
+	            return (exm.VEvaluator.GetInRangeArrayChara(p, min, max, start, end));
+            }
+        }
+        #endregion
+
+        #region 文字列操作系
+        private sealed class StrlenMethod : FunctionMethod
+        {
+            public StrlenMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(string) };
+                CanRestructure = true;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                string str = arguments[0].GetStrValue(exm, true); // JVN: Return TR string's length when necessary
+				str = Translation.translate(str, "ALL", true); //Bartoum : Check if it's not present in all (Ex: Names in gvt for Pedo)
+				//Translation.isStrlens = false;
+                return (LangManager.GetStrlenLang(str));
+            }
+        }
+
+        private sealed class StrlenuMethod : FunctionMethod
+        {
+            public StrlenuMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(string) };
+                CanRestructure = true;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                string str = arguments[0].GetStrValue(exm, true); // JVN: Return TR string's length when necessary
+				str = Translation.translate(str, "ALL", true); //Bartoum : Check if it's not present in all (Ex: Names in gvt for Pedo)
+                return (str.Length);
+            }
+        }
+
+        private sealed class SubstringMethod : FunctionMethod
+        {
+            public SubstringMethod()
+            {
+                ReturnType = typeof(string);
+                argumentTypeArray = null;
+                CanRestructure = true;
+            }
+
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                //通常3つ、2つ省略可能で1~3の引数が必要。
+                if (arguments.Length < 1)
+                    return name + "関数には少なくとも1つの引数が必要です";
+                if (arguments.Length > 3)
+                    return name + "関数の引数が多すぎます";
+
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (arguments[0].GetOperandType() != typeof(string))
+                    return name + "関数の1番目の引数の型が正しくありません";
+                //2、3は省略可能
+                if ((arguments.Length >= 2) && (arguments[1] != null) && (arguments[1].GetOperandType() != typeof(Int64)))
+                    return name + "関数の2番目の引数の型が正しくありません";
+                if ((arguments.Length >= 3) && (arguments[2] != null) && (arguments[2].GetOperandType() != typeof(Int64)))
+                    return name + "関数の3番目の引数の型が正しくありません";
+                return null;
+            }
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+            {
+                string str = arguments[0].GetStrValue(exm);
+                int start = 0;
+                int length = -1;
+                if ((arguments.Length >= 2) && (arguments[1] != null))
+                    start = (int)arguments[1].GetIntValue(exm);
+                if ((arguments.Length >= 3) && (arguments[2] != null))
+                    length = (int)arguments[2].GetIntValue(exm);
+
+                return (LangManager.GetSubStringLang(str, start, length));
+            }
+        }
+
+        private sealed class SubstringuMethod : FunctionMethod
+        {
+            public SubstringuMethod()
+            {
+                ReturnType = typeof(string);
+                argumentTypeArray = null;
+                CanRestructure = true;
+            }
+
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                //通常3つ、2つ省略可能で1~3の引数が必要。
+                if (arguments.Length < 1)
+                    return name + "関数には少なくとも1つの引数が必要です";
+                if (arguments.Length > 3)
+                    return name + "関数の引数が多すぎます";
+
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (arguments[0].GetOperandType() != typeof(string))
+                    return name + "関数の1番目の引数の型が正しくありません";
+                //2、3は省略可能
+                if ((arguments.Length >= 2) && (arguments[1] != null) && (arguments[1].GetOperandType() != typeof(Int64)))
+                    return name + "関数の2番目の引数の型が正しくありません";
+                if ((arguments.Length >= 3) && (arguments[2] != null) && (arguments[2].GetOperandType() != typeof(Int64)))
+                    return name + "関数の3番目の引数の型が正しくありません";
+                return null;
+            }
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+            {
+                string str = arguments[0].GetStrValue(exm);
+                int start = 0;
+                int length = -1;
+                if ((arguments.Length >= 2) && (arguments[1] != null))
+                    start = (int)arguments[1].GetIntValue(exm);
+                if ((arguments.Length >= 3) && (arguments[2] != null))
+                    length = (int)arguments[2].GetIntValue(exm);
+                if ((start >= str.Length) || (length == 0))
+                    return ("");
+                if ((length < 0) || (length > str.Length))
+                    length = str.Length;
+                if (start <= 0)
+                {
+	                if (length == str.Length)
+                        return (str);
+	                start = 0;
+                }
+                if ((start + length) > str.Length)
+                    length = str.Length - start;
+
+                return (str.Substring(start, length));
+            }
+        }
+
+        private sealed class StrfindMethod : FunctionMethod
+        {
+            public StrfindMethod(bool unicode)
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = null;
+                CanRestructure = true;
+				this.unicode = unicode;
+            }
+			bool unicode;
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                //通常3つ、1つ省略可能で2~3の引数が必要。
+                if (arguments.Length < 2)
+                    return name + "関数には少なくとも2つの引数が必要です";
+                if (arguments.Length > 3)
+                    return name + "関数の引数が多すぎます";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (arguments[0].GetOperandType() != typeof(string))
+                    return name + "関数の1番目の引数の型が正しくありません";
+                if (arguments[1] == null)
+                    return name + "関数の2番目の引数は省略できません";
+                if (arguments[1].GetOperandType() != typeof(string))
+                    return name + "関数の2番目の引数の型が正しくありません";
+                //3つ目は省略可能
+                if ((arguments.Length >= 3) && (arguments[2] != null) && (arguments[2].GetOperandType() != typeof(Int64)))
+                    return name + "関数の3番目の引数の型が正しくありません";
+                return null;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+
+                string target = arguments[0].GetStrValue(exm);
+                string word = arguments[1].GetStrValue(exm);
+                int JISstart = 0, UFTstart = 0;
+				if ((arguments.Length >= 3) && (arguments[2] != null))
+				{
+					if (unicode)
+					{
+						UFTstart = (int)arguments[2].GetIntValue(exm);
+					}
+					else
+					{
+						JISstart = (int)arguments[2].GetIntValue(exm);
+						UFTstart = LangManager.GetUFTIndex(target, JISstart);
+					}
+				}
+                if (UFTstart < 0 || UFTstart >= target.Length)
+                    return (-1);
+                int index = target.IndexOf(word, UFTstart);
+				if (index > 0 && !unicode)
+                {
+                    string subStr = target.Substring(0, index);
+                    index = LangManager.GetStrlenLang(subStr);
+                }
+                return (index);
+            }
+        }
+
+        private sealed class StrCountMethod : FunctionMethod
+        {
+            public StrCountMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(string), typeof(string) };
+                CanRestructure = true;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                Regex reg = null;
+                try
+                {
+                    reg = new Regex(arguments[1].GetStrValue(exm));
+                }
+                catch (ArgumentException e)
+                {
+                    throw new CodeEE("第2引数が正規表現として不正です:" + e.Message);
+                }
+                return (reg.Matches(arguments[0].GetStrValue(exm)).Count);
+            }
+        }
+
+        private sealed class ToStrMethod : FunctionMethod
+        {
+            public ToStrMethod()
+            {
+                ReturnType = typeof(string);
+                argumentTypeArray = null;
+                CanRestructure = true;
+            }
+
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                //通常2つ、1つ省略可能で1~2の引数が必要。
+                if (arguments.Length < 1)
+                    return name + "関数には少なくとも1つの引数が必要です";
+                if (arguments.Length > 2)
+                    return name + "関数の引数が多すぎます";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (arguments[0].GetOperandType() != typeof(Int64))
+                    return name + "関数の1番目の引数の型が正しくありません";
+                if ((arguments.Length >= 2) && (arguments[1] != null) && (arguments[1].GetOperandType() != typeof(string)))
+                    return name + "関数の2番目の引数の型が正しくありません";
+                return null;
+            }
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+            {
+                Int64 i = arguments[0].GetIntValue(exm);
+                if ((arguments.Length < 2) || (arguments[1] == null))
+                    return (i.ToString());
+                string format = arguments[1].GetStrValue(exm);
+                string ret;
+                try
+                {
+                    ret = i.ToString(format);
+                }
+                catch (FormatException)
+                {
+                    throw new CodeEE("TOSTR関数の書式指定が間違っています");
+                }
+                return (ret);
+            }
+        }
+
+        private sealed class ToIntMethod : FunctionMethod
+        {
+            public ToIntMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(string) };
+                CanRestructure = true;
+            }
+
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                string str = arguments[0].GetStrValue(exm);
+                if (str == null || str == "")
+                    return (0);
+                //全角文字が入ってるなら無条件で0を返す
+                if (str.Length < LangManager.GetStrlenLang(str))
+                    return (0);
+                StringStream st = new StringStream(str);
+                if (!char.IsDigit(st.Current) && st.Current != '+' && st.Current != '-')
+                    return (0);
+	            if ((st.Current == '+' || st.Current == '-') && !char.IsDigit(st.Next))
+		            return (0);
+	            Int64 ret = LexicalAnalyzer.ReadInt64(st, true);
+                if (!st.EOS)
+                {
+                    if (st.Current == '.')
+                    {
+                        st.ShiftNext();
+                        while (!st.EOS)
+                        {
+                            if (!char.IsDigit(st.Current))
+                                return (0);
+                            st.ShiftNext();
+                        }
+                    }
+                    else
+                        return (0);
+                }
+                return ret;
+            }
+        }
+
+        //難読化用属性。enum.ToString()やenum.Parse()を行うなら(Exclude=true)にすること。
+        [Obfuscation(Exclude = false)]
+        //TOUPPER等の処理を汎用化するためのenum
+        enum StrFormType
+        {
+            Upper = 0,
+            Lower = 1,
+            Half = 2,
+            Full = 3
+        }
+
+        private sealed class StrChangeStyleMethod : FunctionMethod
+        {
+            StrFormType strType;
+
+	        public StrChangeStyleMethod(StrFormType type)
+            {
+                ReturnType = typeof(string);
+                argumentTypeArray = new[] { typeof(string) };
+                strType = type;
+                CanRestructure = true;
+            }
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+            {
+                string str = arguments[0].GetStrValue(exm, tryTranslate);
+                if (str == null || str == "")
+                    return ("");
+                switch (strType)
+                {
+                    case StrFormType.Upper:
+                        return (str.ToUpper());
+                    case StrFormType.Lower:
+                        return (str.ToLower());
+                    case StrFormType.Half:
+                        return (Strings.StrConv(str, VbStrConv.Narrow, Config.Language));
+                    case StrFormType.Full:
+                        return (Strings.StrConv(str, VbStrConv.Wide, Config.Language));
+                }
+                return ("");
+            }
+        }
+
+        private sealed class LineIsEmptyMethod : FunctionMethod
+        {
+            public LineIsEmptyMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new Type[] { };
+                CanRestructure = false;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                return GlobalStatic.Console.EmptyLine ? 1L : 0L;
+            }
+        }
+
+        private sealed class ReplaceMethod : FunctionMethod
+        {
+            //Bartoum : Replace method
+            public ReplaceMethod()
+            {
+                ReturnType = typeof(string);
+                argumentTypeArray = new[] { typeof(string), typeof(string), typeof(string) };
+                CanRestructure = true;
+            }
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+            {
+                string baseString = arguments[0].GetStrValue(exm, tryTranslate);
+                Regex reg;
+                try
+                {
+                    reg = new Regex(arguments[1].GetStrValue(exm, tryTranslate));
+                }
+                catch (ArgumentException e)
+                {
+                    throw new CodeEE("第2引数が正規表現として不正です:" + e.Message);
+                }
+                return (reg.Replace(baseString, arguments[2].GetStrValue(exm, tryTranslate)));
+            }
+        }
+
+        private sealed class UnicodeMethod : FunctionMethod
+        {
+            public UnicodeMethod()
+            {
+                ReturnType = typeof(string);
+                argumentTypeArray = new[] { typeof(Int64) };
+                CanRestructure = true;
+            }
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+            {
+                Int64 i = arguments[0].GetIntValue(exm);
+                if ((i < 0) || (i > 0xFFFF))
+                    throw new CodeEE("UNICODE関数に範囲外の値(" + i + ")が渡されました");
+                string s = new string(new[] { (char)i });// char.ConvertFromUtf32(i);
+
+                return (s);
+            }
+        }
+
+        private sealed class UnicodeByteMethod : FunctionMethod
+        {
+            public UnicodeByteMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(string) };
+                CanRestructure = true;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                string target = arguments[0].GetStrValue(exm);
+                int length = Encoding.UTF32.GetEncoder().GetByteCount(target.ToCharArray(), 0, target.Length, false);
+                byte[] bytes = new byte[length];
+                Encoding.UTF32.GetEncoder().GetBytes(target.ToCharArray(), 0, target.Length, bytes, 0, false);
+                Int64 i = BitConverter.ToInt32(bytes, 0);
+
+                return (i);
+            }
+        }
+
+        private sealed class ConvertIntMethod : FunctionMethod
+        {
+            public ConvertIntMethod()
+            {
+                ReturnType = typeof(string);
+                argumentTypeArray = new[] { typeof(Int64), typeof(Int64) };
+                CanRestructure = true;
+            }
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+            {
+                Int64 toBase = arguments[1].GetIntValue(exm);
+                if ((toBase != 2) && (toBase != 8) && (toBase != 10) && (toBase != 16))
+                    throw new CodeEE("CONVERT関数の第2引数は2, 8, 10, 16のいずれかでなければなりません");
+                return Convert.ToString(arguments[0].GetIntValue(exm), (int)toBase);
+            }
+        }
+
+        private sealed class IsNumericMethod : FunctionMethod
+        {
+            public IsNumericMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new[] { typeof(string) };
+                CanRestructure = true;
+            }
+            public override long GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                string baseStr = arguments[0].GetStrValue(exm);
+
+                //全角文字があるなら数値ではない
+                if (baseStr.Length < LangManager.GetStrlenLang(baseStr))
+                    return (0);
+                StringStream st = new StringStream(baseStr);
+                if (!char.IsDigit(st.Current) && st.Current != '+' && st.Current != '-')
+                    return (0);
+	            if ((st.Current == '+' || st.Current == '-') && !char.IsDigit(st.Next))
+		            return (0);
+	            Int64 ret = LexicalAnalyzer.ReadInt64(st, true);
+                if (!st.EOS)
+                {
+                    if (st.Current == '.')
+                    {
+                        st.ShiftNext();
+                        while (!st.EOS)
+                        {
+                            if (!char.IsDigit(st.Current))
+                                return (0);
+                            st.ShiftNext();
+                        }
+                    }
+                    else
+                        return (0);
+                }
+                return 1;
+            }
+        }
+
+        private sealed class EscapeMethod : FunctionMethod
+        {
+            public EscapeMethod()
+            {
+                ReturnType = typeof(string);
+                argumentTypeArray = new[] { typeof(string) };
+                CanRestructure = true;
+            }
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+            {
+                return Regex.Escape(arguments[0].GetStrValue(exm));
+            }
+        }
+
+        private sealed class EncodeToUniMethod : FunctionMethod
+        {
+            public EncodeToUniMethod()
+            {
+                ReturnType = typeof(Int64);
+                argumentTypeArray = new Type[] { null };
+                CanRestructure = true;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                //通常2つ、1つ省略可能で1~2の引数が必要。
+                if (arguments.Length < 1)
+                    return name + "関数には少なくとも1つの引数が必要です";
+                if (arguments.Length > 2)
+                    return name + "関数の引数が多すぎます";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (arguments[0].GetOperandType() != typeof(string))
+                    return name + "関数の1番目の引数の型が正しくありません";
+                if ((arguments.Length >= 2) && (arguments[1] != null) && (arguments[1].GetOperandType() != typeof(Int64)))
+                    return name + "関数の2番目の引数の型が正しくありません";
+                return null;
+            }
+            public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                string baseStr = arguments[0].GetStrValue(exm);
+                if (baseStr.Length == 0)
+                    return -1;
+                Int64 position = (arguments.Length > 1 && arguments[1] != null) ? arguments[1].GetIntValue(exm) : 0;
+                if (position < 0)
+                    throw new CodeEE("ENCOIDETOUNI関数の第2引数(" + position + ")が負の値です");
+                if (position >= baseStr.Length)
+                    throw new CodeEE("ENCOIDETOUNI関数の第2引数(" + position + ")が第1引数の文字列(" + baseStr + ")の文字数を超えています");
+                return char.ConvertToUtf32(baseStr, (int)position);
+            }
+        }
+
+        public sealed class CharAtMethod : FunctionMethod
+        {
+            public CharAtMethod()
+            {
+                ReturnType = typeof(string);
+                argumentTypeArray = new[] { typeof(string), typeof(Int64) };
+                CanRestructure = true;
+            }
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+            {
+                string str = arguments[0].GetStrValue(exm);
+                Int64 pos = arguments[1].GetIntValue(exm);
+                if (pos < 0 || pos >= str.Length)
+                    return "";
+                return str[(int)pos].ToString();
+            }
+        }
+
+        public sealed class GetLineStrMethod : FunctionMethod
+        {
+            public GetLineStrMethod()
+            {
+                ReturnType = typeof(string);
+                argumentTypeArray = new[] { typeof(string) };
+                CanRestructure = true;
+            }
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+			{
+                string str = arguments[0].GetStrValue(exm);
+				if (string.IsNullOrEmpty(str))
+					throw new CodeEE("GETLINESTR関数の引数が空文字列です");
+                return exm.Console.getStBar(str);
+            }
+        }
+
+		public sealed class StrFormMethod : FunctionMethod
+		{
+			public StrFormMethod()
+			{
+				ReturnType = typeof(string);
+				argumentTypeArray = new[] { typeof(string) };
+                HasUniqueRestructure = true;
+				CanRestructure = true;
+			}
+			public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+			{
+				string str = arguments[0].GetStrValue(exm, tryTranslate);
+				string destStr = str;
+				try
+				{
+					StrFormWord wt = LexicalAnalyzer.AnalyseFormattedString(new StringStream(str), FormStrEndWith.EoL, false);
+					StrForm strForm = StrForm.FromWordToken(wt);
+					destStr = strForm.GetString(exm, tryTranslate);
+				}
+				catch(CodeEE e)
+				{
+					throw new CodeEE("STRFORM関数:文字列\"" + str + "\"の展開エラー:" + e.Message);
+				}
+				catch
+				{
+					throw new CodeEE("STRFORM関数:文字列\"" + str+ "\"の展開処理中にエラーが発生しました");
+				}
+				return destStr;
+			}
+            public override bool UniqueRestructure(ExpressionMediator exm, IOperandTerm[] arguments)
+            {
+                arguments[0].Restructure(exm);
+                //引数が文字列式等ならお手上げなので諦める
+                if (!(arguments[0] is SingleTerm) && !(arguments[0] is VariableTerm))
+                    return false;
+                //引数が確定値でない文字列変数なら無条件で不可(結果が可変なため)
+                if ((arguments[0] is VariableTerm) && !(((VariableTerm)arguments[0]).Identifier.IsConst))
+                    return false;
+                string str = arguments[0].GetStrValue(exm);
+                try
+                {
+                    StrFormWord wt = LexicalAnalyzer.AnalyseFormattedString(new StringStream(str), FormStrEndWith.EoL, false);
+                    StrForm strForm = StrForm.FromWordToken(wt);
+                    if (!strForm.IsConst)
+                        return false;
+                }
+                catch
+                {
+                    //パースできないのはエラーがあるかここではわからないからとりあえず考えない
+                    return false;
+                }
+                return true;
+            }
+        }
+
+        public sealed class JoinMethod : FunctionMethod
+        {
+            public JoinMethod()
+            {
+                ReturnType = typeof(string);
+                argumentTypeArray = null;
+                HasUniqueRestructure = false;
+                CanRestructure = false;
+            }
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                if (arguments.Length < 1)
+                    return name + "関数には少なくとも1つの引数が必要です";
+                if (arguments.Length > 4)
+                    return name + "関数の引数が多すぎます";
+                if (arguments[0] == null)
+                    return name + "関数の1番目の引数は省略できません";
+                if (!(arguments[0] is VariableTerm))
+                    return name + "関数の1番目の引数が変数ではありません";
+                VariableTerm varToken = (VariableTerm)arguments[0];
+                if (!varToken.Identifier.IsArray1D && !varToken.Identifier.IsArray2D && !varToken.Identifier.IsArray3D)
+                    return name + "関数の1番目の引数が配列変数ではありません";
+                if (arguments.Length == 1)
+                    return null;
+                if ((arguments[1] != null) && (arguments[1].GetOperandType() != typeof(string)))
+                    return name + "関数の2番目の変数が文字列ではありません";
+                if (arguments.Length == 2)
+                    return null;
+                if ((arguments[2] != null) && (arguments[2].GetOperandType() != typeof(Int64)))
+                    return name + "関数の3番目の変数が数値ではありません";
+                if (arguments.Length == 3)
+                    return null;
+                if ((arguments[3] != null) && (arguments[3].GetOperandType() != typeof(Int64)))
+                    return name + "関数の4番目の変数が数値ではありません";
+                return null;
+            }
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = true)
+            {
+                VariableTerm varTerm = (VariableTerm)arguments[0];
+                string delimiter = (arguments.Length >= 2 && arguments[1] != null) ? arguments[1].GetStrValue(exm) : ",";
+                Int64 index1 = (arguments.Length >= 3 && arguments[2] != null) ? arguments[2].GetIntValue(exm) : 0;
+                Int64 index2 = (arguments.Length == 4 && arguments[3] != null) ? arguments[3].GetIntValue(exm) : varTerm.GetLastLength();
+
+                FixedVariableTerm p = varTerm.GetFixedVariableTerm(exm);
+
+                p.IsArrayRangeValid(index1, index2, "STRJOIN", 2L, 3L);
+                return (exm.VEvaluator.GetJoinedStr(p, delimiter, index1, index2));
+            }
+        }
+
+		public sealed class GetConfigMethod : FunctionMethod
+		{
+			public GetConfigMethod(bool typeisInt)
+			{
+				if(typeisInt)
+				{
+					funcname = "GETCONFIG";
+					ReturnType = typeof(Int64);
+				}
+				else
+				{
+					funcname = "GETCONFIGS";
+					ReturnType = typeof(string);
+				}
+				argumentTypeArray = new[] { typeof(string) };
+				CanRestructure = true;
+			}
+			private readonly string funcname;
+			private SingleTerm getSingleTerm(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				string str = arguments[0].GetStrValue(exm);
+				if(str == null || str.Length == 0)
+					throw new CodeEE(funcname + "関数に空文字列が渡されました");
+				string errMes = null;
+				SingleTerm term = ConfigData.Instance.GetConfigValueInERB(str, ref errMes);
+				if(errMes != null)
+					throw new CodeEE(funcname + "関数:" + errMes);
+				return term;
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments)
+			{
+				if(ReturnType != typeof(Int64))
+					throw new ExeEE(funcname + "関数:不正な呼び出し");
+				SingleTerm term = getSingleTerm(exm, arguments);
+				if(term.GetOperandType() != typeof(Int64))
+					throw new CodeEE(funcname + "関数:型が違います(GETCONFIGS関数を使用してください)");
+				return term.Int;
+			}
+			public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+			{
+				if(ReturnType != typeof(string))
+					throw new ExeEE(funcname + "関数:不正な呼び出し");
+				SingleTerm term = getSingleTerm(exm, arguments);
+				if (term.GetOperandType() != typeof(string))
+					throw new CodeEE(funcname + "関数:型が違います(GETCONFIG関数を使用してください)");
+				return term.Str;
+			}
+		}
+        #endregion
+
+		#region html系
+
+		private sealed class HtmlGetPrintedStrMethod : FunctionMethod
+		{
+			public HtmlGetPrintedStrMethod()
+			{
+				ReturnType = typeof(string);
+				argumentTypeArray = null;
+				CanRestructure = false;
+			}
+
+			public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+			{
+				//通常1つ。省略可能。
+				if (arguments.Length > 1)
+					return name + "関数の引数が多すぎます";
+				if (arguments.Length == 0|| arguments[0] == null)
+					return null;
+				if (arguments[0].GetOperandType() != typeof(Int64))
+					return name + "関数の1番目の引数の型が正しくありません";
+				return null;
+			}
+			public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+			{
+				Int64 lineNo = 0;
+				if (arguments.Length > 0)
+					lineNo = arguments[0].GetIntValue(exm);
+				if (lineNo < 0)
+					throw new CodeEE("引数を0未満にできません");
+				ConsoleDisplayLine[] dispLines = exm.Console.GetDisplayLines(lineNo);
+				if (dispLines == null)
+					return "";
+
+                return HtmlManager.DisplayLine2Html(dispLines, true);
+			}
+		}
+
+		private sealed class HtmlPopPrintingStrMethod : FunctionMethod
+		{
+			public HtmlPopPrintingStrMethod()
+			{
+				ReturnType = typeof(string);
+				argumentTypeArray = new Type[] { };
+				CanRestructure = false;
+			}
+
+			public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+			{
+				ConsoleDisplayLine[] dispLines = exm.Console.PopDisplayingLines();
+				if (dispLines == null)
+					return "";
+				return HtmlManager.DisplayLine2Html(dispLines, false);
+			}
+		}
+
+		private sealed class HtmlToPlainTextMethod : FunctionMethod
+		{
+			public HtmlToPlainTextMethod()
+			{
+				ReturnType = typeof(string);
+                argumentTypeArray = new[] { typeof(string) };
+				CanRestructure = false;
+			}
+			public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+			{
+				return HtmlManager.Html2PlainText(arguments[0].GetStrValue(exm));
+			}
+		}
+		private sealed class HtmlEscapeMethod : FunctionMethod
+		{
+			public HtmlEscapeMethod()
+			{
+				ReturnType = typeof(string);
+                argumentTypeArray = new[] { typeof(string) };
+				CanRestructure = false;
+			}
+			public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+			{
+				return HtmlManager.Escape(arguments[0].GetStrValue(exm));
+			}
+		}
+		#endregion
+	}
+}

+ 154 - 0
NTERA/Game/GameData/Function/Creator.cs

@@ -0,0 +1,154 @@
+using System.Collections.Generic;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameData.Function
+{
+	internal static partial class FunctionMethodCreator
+	{
+		static FunctionMethodCreator()
+		{
+			methodList = new Dictionary<string, FunctionMethod>();
+            //キャラクタデータ系
+			methodList["GETCHARA"] = new GetcharaMethod();
+			methodList["GETSPCHARA"] = new GetspcharaMethod();
+			methodList["CSVNAME"] = new CsvStrDataMethod(CharacterStrData.NAME);
+			methodList["CSVCALLNAME"] = new CsvStrDataMethod(CharacterStrData.CALLNAME);
+			methodList["CSVNICKNAME"] = new CsvStrDataMethod(CharacterStrData.NICKNAME);
+			methodList["CSVMASTERNAME"] = new CsvStrDataMethod(CharacterStrData.MASTERNAME);
+			methodList["CSVCSTR"] = new CsvcstrMethod();
+			methodList["CSVBASE"] = new CsvDataMethod(CharacterIntData.BASE);
+			methodList["CSVABL"] = new CsvDataMethod(CharacterIntData.ABL);
+			methodList["CSVMARK"] = new CsvDataMethod(CharacterIntData.MARK);
+			methodList["CSVEXP"] = new CsvDataMethod(CharacterIntData.EXP);
+			methodList["CSVRELATION"] = new CsvDataMethod(CharacterIntData.RELATION);
+			methodList["CSVTALENT"] = new CsvDataMethod(CharacterIntData.TALENT);
+			methodList["CSVCFLAG"] = new CsvDataMethod(CharacterIntData.CFLAG);
+			methodList["CSVEQUIP"] = new CsvDataMethod(CharacterIntData.EQUIP);
+			methodList["CSVJUEL"] = new CsvDataMethod(CharacterIntData.JUEL);
+            methodList["FINDCHARA"] = new FindcharaMethod(false);
+            methodList["FINDLASTCHARA"] = new FindcharaMethod(true);
+            methodList["EXISTCSV"] = new ExistCsvMethod();
+
+            //汎用処理系
+			methodList["VARSIZE"] = new VarsizeMethod();
+			methodList["CHKFONT"] = new CheckfontMethod();
+			methodList["CHKDATA"] = new CheckdataMethod("CHKDATA", EraSaveFileType.Normal);
+            methodList["ISSKIP"] = new IsSkipMethod();
+			methodList["MOUSESKIP"] = new MesSkipMethod(true);
+			methodList["MESSKIP"] = new MesSkipMethod(false);
+            methodList["GETCOLOR"] = new GetColorMethod(false);
+            methodList["GETDEFCOLOR"] = new GetColorMethod(true);
+            methodList["GETFOCUSCOLOR"] = new GetFocusColorMethod();
+            methodList["GETBGCOLOR"] = new GetBGColorMethod(false);
+            methodList["GETDEFBGCOLOR"] = new GetBGColorMethod(true);
+            methodList["GETSTYLE"] = new GetStyleMethod();
+            methodList["GETFONT"] = new GetFontMethod();
+            methodList["BARSTR"] = new BarStringMethod();
+            methodList["CURRENTALIGN"] = new CurrentAlignMethod();
+			methodList["CURRENTREDRAW"] = new CurrentRedrawMethod();
+			methodList["COLOR_FROMNAME"] = new ColorFromNameMethod();
+			methodList["COLOR_FROMRGB"] = new ColorFromRGBMethod();
+
+			//TODO:1810
+			//methodList["CHKVARDATA"] = new CheckdataStrMethod("CHKVARDATA", EraSaveFileType.Var);
+			methodList["CHKCHARADATA"] = new CheckdataStrMethod("CHKCHARADATA", EraSaveFileType.CharVar);
+			//methodList["CHKGLOBALDATA"] = new CheckdataMethod("CHKGLOBALDATA", EraSaveFileType.Global);
+			//methodList["FIND_VARDATA"] = new FindFilesMethod("FIND_VARDATA", EraSaveFileType.Var);
+			methodList["FIND_CHARADATA"] = new FindFilesMethod("FIND_CHARADATA", EraSaveFileType.CharVar);
+
+            //定数取得
+            methodList["MONEYSTR"] = new MoneyStrMethod();
+            methodList["PRINTCPERLINE"] = new GetPrintCPerLineMethod();
+			methodList["PRINTCLENGTH"] = new PrintCLengthMethod(); 
+            methodList["SAVENOS"] = new GetSaveNosMethod();
+            methodList["GETTIME"] = new GettimeMethod();
+            methodList["GETTIMES"] = new GettimesMethod();
+            methodList["GETMILLISECOND"] = new GetmsMethod();
+            methodList["GETSECOND"] = new GetSecondMethod();
+
+            //数学関数
+			methodList["RAND"] = new RandMethod();
+			methodList["MIN"] = new MaxMethod(false);
+			methodList["MAX"] = new MaxMethod(true);
+			methodList["ABS"] = new AbsMethod();
+			methodList["POWER"] = new PowerMethod();
+			methodList["SQRT"] = new SqrtMethod();
+			methodList["CBRT"] = new CbrtMethod();
+			methodList["LOG"] = new LogMethod();
+			methodList["LOG10"] = new LogMethod(10.0d);
+			methodList["EXPONENT"] = new ExpMethod();
+			methodList["SIGN"] = new SignMethod();
+            methodList["LIMIT"] = new GetLimitMethod();
+
+            //変数操作系
+			methodList["SUMARRAY"] = new SumArrayMethod();
+			methodList["SUMCARRAY"] = new SumArrayMethod(true);
+			methodList["MATCH"] = new MatchMethod();
+			methodList["CMATCH"] = new MatchMethod(true);
+			methodList["GROUPMATCH"] = new GroupMatchMethod();
+			methodList["NOSAMES"] = new NosamesMethod();
+			methodList["ALLSAMES"] = new AllsamesMethod();
+			methodList["MAXARRAY"] = new MaxArrayMethod();
+			methodList["MAXCARRAY"] = new MaxArrayMethod(true);
+			methodList["MINARRAY"] = new MaxArrayMethod(false, false);
+			methodList["MINCARRAY"] = new MaxArrayMethod(true, false);
+			methodList["GETBIT"] = new GetbitMethod();
+			methodList["GETNUM"] = new GetnumMethod();
+			methodList["GETPALAMLV"] = new GetPalamLVMethod();
+			methodList["GETEXPLV"] = new GetExpLVMethod();
+            methodList["FINDELEMENT"] = new FindElementMethod(false);
+            methodList["FINDLASTELEMENT"] = new FindElementMethod(true);
+            methodList["INRANGE"] = new InRangeMethod();
+            methodList["INRANGEARRAY"] = new InRangeArrayMethod();
+			methodList["INRANGECARRAY"] = new InRangeArrayMethod(true);
+			methodList["GETNUMB"] = new GetnumMethod();
+
+
+            //文字列操作系
+            methodList["STRLENS"] = new StrlenMethod();
+            methodList["STRLENSU"] = new StrlenuMethod();
+            methodList["SUBSTRING"] = new SubstringMethod();
+            methodList["SUBSTRINGU"] = new SubstringuMethod();
+            methodList["STRFIND"] = new StrfindMethod(false);
+            methodList["STRFINDU"] = new StrfindMethod(true);
+            methodList["STRCOUNT"] = new StrCountMethod();
+			methodList["TOSTR"] = new ToStrMethod();
+			methodList["TOINT"] = new ToIntMethod();
+			methodList["TOUPPER"] = new StrChangeStyleMethod(StrFormType.Upper);
+			methodList["TOLOWER"] = new StrChangeStyleMethod(StrFormType.Lower);
+			methodList["TOHALF"] = new StrChangeStyleMethod(StrFormType.Half);
+			methodList["TOFULL"] = new StrChangeStyleMethod(StrFormType.Full);
+			methodList["LINEISEMPTY"] = new LineIsEmptyMethod();
+			methodList["REPLACE"] = new ReplaceMethod();
+            methodList["UNICODE"] = new UnicodeMethod();
+            methodList["UNICODEBYTE"] = new UnicodeByteMethod();
+			methodList["CONVERT"] = new ConvertIntMethod();
+            methodList["ISNUMERIC"] = new IsNumericMethod();
+            methodList["ESCAPE"] = new EscapeMethod();
+            methodList["ENCODETOUNI"] = new EncodeToUniMethod();
+            methodList["CHARATU"] = new CharAtMethod();
+			methodList["GETLINESTR"] = new GetLineStrMethod();
+			methodList["STRFORM"] = new StrFormMethod();
+            methodList["STRJOIN"] = new JoinMethod();
+			
+			methodList["GETCONFIG"] = new GetConfigMethod(true);
+			methodList["GETCONFIGS"] = new GetConfigMethod(false);
+
+			//html系
+			methodList["HTML_GETPRINTEDSTR"] = new HtmlGetPrintedStrMethod();
+			methodList["HTML_POPPRINTINGSTR"] = new HtmlPopPrintingStrMethod();
+			methodList["HTML_TOPLAINTEXT"] = new HtmlToPlainTextMethod();
+			methodList["HTML_ESCAPE"] = new HtmlEscapeMethod();
+
+            // JVN: TR Commands here
+            methodList["TR_NAME"] = new TRNameMethod();
+            //methodList["TR_CSTR"] = new TRCSTRMethod();
+        }
+
+        private static Dictionary<string, FunctionMethod> methodList;
+		public static Dictionary<string, FunctionMethod> GetMethodList()
+		{
+			return methodList;
+		}
+	}
+}

+ 55 - 0
NTERA/Game/GameData/Function/FunctionMethod.cs

@@ -0,0 +1,55 @@
+using System;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameData.Function
+{
+	internal abstract class FunctionMethod
+	{
+		public Type ReturnType { get; protected set; }
+		protected Type[] argumentTypeArray;
+
+		//引数の数・型が一致するかどうかのテスト
+		//正しくない場合はエラーメッセージを返す。
+		//引数の数が不定である場合や引数の省略を許す場合にはoverrideすること。
+		public virtual string CheckArgumentType(string name, IOperandTerm[] arguments)
+		{
+			if (arguments.Length != argumentTypeArray.Length)
+				return name + "関数の引数の数が正しくありません";
+			for (int i = 0; i < argumentTypeArray.Length; i++)
+			{
+				if (arguments[i] == null)
+					return name + "関数の" + (i + 1) + "番目の引数は省略できません";
+				if (argumentTypeArray[i] != arguments[i].GetOperandType())
+					return name + "関数の" +(i+1)+ "番目の引数の型が正しくありません";
+			}
+			return null;
+		}
+		
+		//Argumentが全て定数の時にMethodを解体してよいかどうか。RANDやCharaを参照するものなどは不可
+		public bool CanRestructure { get; protected set; }
+
+		//FunctionMethodが固有のRestructure()を持つかどうか
+		public bool HasUniqueRestructure { get; protected set; }
+
+		//実際の計算。
+		public virtual Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments) { throw new ExeEE("戻り値の型が違う or 未実装"); }
+		public virtual string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false) { throw new ExeEE("戻り値の型が違う or 未実装"); }
+		public virtual SingleTerm GetReturnValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate)
+		{
+			if (ReturnType == typeof(Int64))
+				return new SingleTerm(GetIntValue(exm, arguments));
+			return new SingleTerm(GetStrValue(exm, arguments));
+		}
+
+		/// <summary>
+		/// 戻り値は全体をRestructureできるかどうか
+		/// </summary>
+		/// <param name="exm"></param>
+		/// <param name="arguments"></param>
+		/// <returns></returns>
+		public virtual bool UniqueRestructure(ExpressionMediator exm, IOperandTerm[] arguments)
+		{ throw new ExeEE("未実装?"); }
+		
+	}
+}

+ 56 - 0
NTERA/Game/GameData/Function/FunctionMethodTerm.cs

@@ -0,0 +1,56 @@
+using MinorShift.Emuera.GameData.Expression;
+
+namespace MinorShift.Emuera.GameData.Function
+{
+	internal sealed class FunctionMethodTerm : IOperandTerm
+	{
+		public FunctionMethodTerm(FunctionMethod meth, IOperandTerm[] args)
+			: base(meth.ReturnType)
+		{
+			method = meth;
+			arguments = args;
+		}
+
+		private FunctionMethod method;
+		private IOperandTerm[] arguments;
+
+        public override long GetIntValue(ExpressionMediator exm)
+        {
+			return method.GetIntValue(exm, arguments);
+        }
+        public override string GetStrValue(ExpressionMediator exm, bool translate=false)
+        {
+			return method.GetStrValue(exm, arguments, translate);
+        }
+		public override SingleTerm GetValue(ExpressionMediator exm, bool tryTranslate =false)
+		{
+			return method.GetReturnValue(exm, arguments, tryTranslate);
+		}
+		
+        public override IOperandTerm Restructure(ExpressionMediator exm, bool tryTranslate=false)
+        {
+			if (method.HasUniqueRestructure)
+			{
+				if (method.UniqueRestructure(exm, arguments) && method.CanRestructure)
+					return GetValue(exm);
+				return this;
+			}
+			bool argIsConst = true;
+			for(int i = 0; i< arguments.Length;i++)
+			{
+				if(arguments[i] == null)
+					continue;
+				//Changes by Bartoum
+				
+				//This is a place to rework. This is where constant are translated
+				arguments[i] = arguments[i].Restructure(exm, true);
+				argIsConst &= arguments[i] is SingleTerm;
+			}
+			if ((method.CanRestructure) && (argIsConst))
+				return GetValue(exm);
+			return this;
+			
+        }
+        
+	}
+}

+ 293 - 0
NTERA/Game/GameData/Function/TRCommands.cs

@@ -0,0 +1,293 @@
+using System;
+using System.Collections.Generic;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameData.Function
+{
+    internal static partial class FunctionMethodCreator
+    {
+        // str TR_NAME(str,str)
+        // Input 1: string with csv key or 
+        // Input 2: string with csv value or int identifier
+        // Output: String with TR-translated if it's successful found, or the original if it fails
+        public sealed class TRNameMethod : FunctionMethod
+        {
+
+            public TRNameMethod()
+            {
+                ReturnType = typeof(string);
+                argumentTypeArray = null;
+                CanRestructure = true;
+            }
+
+            public override string CheckArgumentType(string name, IOperandTerm[] arguments)
+            {
+                if (arguments.Length < 2)
+                    return name + " needs 2 arguments";
+                if (arguments.Length > 2)
+                    return name + " has too many arguments";
+                if (arguments[0] == null)
+                    return "1st argument of " + name + " cannot be ommited";
+                if (!(arguments[0].GetOperandType() == typeof(string) || arguments[0] is VariableTerm))
+                    return "1st argument of " + name + " must be a string or term";
+                if (arguments[1] == null)
+                    return "2nd argument of " + name + " cannot be ommited";
+                if (!(arguments[1].GetOperandType() == typeof(Int64) || arguments[1].GetOperandType() == typeof(string)))
+                    return "2nd argument of " + name + " must be a string or int";
+                return null;
+            }
+
+            public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+            {
+                string sdic = "";
+                VariableCode varCode;
+                if (arguments[0].GetOperandType() == typeof(string)) { // JVN: If first argument is a string...
+                    sdic = arguments[0].GetStrValue(exm);
+                    switch (sdic)
+                    { // JVN: Prepares the first argument
+                        case "ABL":
+                        case "ABLNAME":
+                            sdic = "Abl";
+                            varCode = VariableCode.ABL;
+                            break;
+                        case "BASE":
+                        case "BASENAME":
+                            sdic = "Base";
+                            varCode = VariableCode.BASE;
+                            break;
+                        case "CDFLAG1":
+                        case "CDFLAGNAME1":
+                            sdic = "Cdflag1";
+                            varCode = VariableCode.CDFLAGNAME1;
+                            break;
+                        case "CDFLAG2":
+                        case "CDFLAGNAME2":
+                            sdic = "Cdflag2";
+                            varCode = VariableCode.CDFLAGNAME2;
+                            break;
+                        case "CFLAG":
+                        case "CFLAGNAME":
+                            sdic = "Cflag";
+                            varCode = VariableCode.CFLAG;
+                            break;
+                        case "CSTR":
+                        case "CSTRNAME":
+                            sdic = "CSTR";
+                            varCode = VariableCode.CSTR;
+                            break;
+                        case "EQUIP":
+                        case "EQUIPNAME":
+                            sdic = "EQUIP";
+                            varCode = VariableCode.EQUIP;
+                            break;
+                        case "EX":
+                        case "EXNAME":
+                            sdic = "Ex";
+                            varCode = VariableCode.EX;
+                            break;
+                        case "EXP":
+                        case "EXPNAME":
+                            sdic = "Exp";
+                            varCode = VariableCode.EXP;
+                            break;
+                        case "FLAG":
+                        case "FLAGNAME":
+                            sdic = "Flag";
+                            varCode = VariableCode.FLAG;
+                            break;
+                        case "GLOBAL":
+                        case "GLOBALNAME":
+                            sdic = "GLOBAL";
+                            varCode = VariableCode.GLOBAL;
+                            break;
+                        case "GLOBALS":
+                        case "GLOBALSNAME":
+                            sdic = "GLOBALS";
+                            varCode = VariableCode.GLOBALS;
+                            break;
+                        case "ITEM":
+                        case "ITEMNAME":
+                            sdic = "Item";
+                            varCode = VariableCode.ITEM;
+                            break;
+                        case "MARK":
+                        case "MARKNAME":
+                            sdic = "Mark";
+                            varCode = VariableCode.MARK;
+                            break;
+                        case "PALAM":
+                        case "PALAMNAME":
+                        case "PARAM":
+                        case "PARAMNAME":
+                            sdic = (Translation.isCanLoadParam() ? "Param" : "Palam");
+                            varCode = VariableCode.PALAM;
+                            break;
+                        case "SAVESTR":
+                        case "SAVESTRNAME":
+                            sdic = "SaveStr";
+                            varCode = VariableCode.SAVESTR;
+                            break;
+                        case "SOURCE":
+                        case "SOURCENAME":
+                            sdic = "Source";
+                            varCode = VariableCode.SOURCE;
+                            break;
+                        case "STAIN":
+                        case "STAINNAME":
+                            sdic = "Stain";
+                            varCode = VariableCode.STAIN;
+                            break;
+                        case "STR":
+                        case "STRNAME":
+                            sdic = "Str";
+                            varCode = VariableCode.STR;
+                            break;
+                        case "TALENT":
+                        case "TALENTNAME":
+                            sdic = "Talent";
+                            varCode = VariableCode.TALENT;
+                            break;
+                        case "TCVAR":
+                        case "TCVARNAME":
+                            sdic = "Tcvar";
+                            varCode = VariableCode.TCVAR;
+                            break;
+                        case "TEQUIP":
+                        case "TEQUIPNAME":
+                            sdic = "TEQUIP";
+                            varCode = VariableCode.TEQUIP;
+                            break;
+                        case "TFLAG":
+                        case "TFLAGNAME":
+                            sdic = "TFLAG";
+                            varCode = VariableCode.TFLAG;
+                            break;
+                        case "TRAIN":
+                        case "TRAINNAME":
+                            sdic = "Train";
+                            varCode = VariableCode.TRAINNAME;
+                            break;
+                        case "TSTR":
+                        case "TSTRNAME":
+                            sdic = "TSTR";
+                            varCode = VariableCode.TSTR;
+                            break;
+                        default:
+                            throw new CodeEE("Invalid first argument: " + arguments[0].GetStrValue(exm));
+                    }
+                }
+                else { //JVN: first argument must be a variable term
+                    VariableTerm vToken = (VariableTerm)arguments[0];
+                    varCode = vToken.Identifier.Code;
+                    switch (varCode)
+                    {
+                        case VariableCode.ABL:
+                            sdic = "Abl";
+                            break;
+                        case VariableCode.BASE:
+                            sdic = "Base";
+                            break;
+                        case VariableCode.CDFLAGNAME1:
+                            sdic = "Cdflag1";
+                            break;
+                        case VariableCode.CDFLAGNAME2:
+                            sdic = "Cdflag2";
+                            break;
+                        case VariableCode.CFLAG:
+                            sdic = "Cflag";
+                            break;
+                        case VariableCode.CSTR:
+                            sdic = "CSTR";
+                            break;
+                        case VariableCode.EQUIP:
+                            sdic = "EQUIP";
+                            break;
+                        case VariableCode.EX:
+                            sdic = "Ex";
+                            break;
+                        case VariableCode.EXP:
+                            sdic = "Exp";
+                            break;
+                        case VariableCode.FLAG:
+                            sdic = "Flag";
+                            break;
+                        case VariableCode.GLOBAL:
+                            sdic = "GLOBAL";
+                            break;
+                        case VariableCode.GLOBALS:
+                            sdic = "GLOBALS";
+                            break;
+                        case VariableCode.ITEM:
+                            sdic = "Item";
+                            break;
+                        case VariableCode.MARK:
+                            sdic = "Mark";
+                            break;
+                        case VariableCode.PALAM:
+                            sdic = (Translation.isCanLoadParam() ? "Param" : "Palam");
+                            break;
+                        case VariableCode.SAVESTR:
+                            sdic = "SaveStr";
+                            break;
+                        case VariableCode.SOURCE:
+                            sdic = "Source";
+                            break;
+                        case VariableCode.STAIN:
+                            sdic = "Stain";
+                            break;
+                        case VariableCode.STR:
+                            sdic = "Str";
+                            break;
+                        case VariableCode.TALENT:
+                            sdic = "Talent";
+                            break;
+                        case VariableCode.TCVAR:
+                            sdic = "Tcvar";
+                            break;
+                        case VariableCode.TEQUIP:
+                            sdic = "TEQUIP";
+                            break;
+                        case VariableCode.TFLAG:
+                            sdic = "TFLAG";
+                            break;
+                        case VariableCode.TRAINNAME:
+                            sdic = "Train";
+                            break;
+                        case VariableCode.TSTR:
+                            sdic = "TSTR";
+                            break;
+                        default:
+                            throw new CodeEE("Invalid first argument: " + vToken);
+                    }
+                }
+                if (arguments[1].GetOperandType() == typeof(string)) { // JVN: Deal with the string
+                    string key = arguments[1].GetStrValue(exm);
+                    if (exm.VEvaluator.Constant.isDefined(varCode, key)) return Translation.translate(key, sdic, true);
+	                throw new CodeEE("Invalid second argument: " + arguments[1].GetStrValue(exm));
+                }
+
+	            // JVN: Deal with the integer
+	            string errPos;
+	            Dictionary<string, int> dic = exm.VEvaluator.Constant.GetKeywordDictionary(out errPos, varCode, -1);
+	            if (dic != null) {
+		            foreach (var entry in dic) 
+			            if (entry.Value == arguments[1].GetIntValue(exm)) return Translation.translate(entry.Key,sdic,true);
+
+		            throw new CodeEE("Invalid second argument: " + arguments[1].GetIntValue(exm));
+	            }
+
+	            throw new CodeEE("Invalid second argument: " + arguments[1].GetIntValue(exm));
+
+	            // JVN: Should never get here
+                throw new CodeEE("Unknown Error");
+            }
+        }
+
+        /*public sealed class TRCSTRMethod : FunctionMethod
+        {
+            //return exm.VEvaluator.GetCharacterStrfromCSVData(x, varCode, false, 0);
+        }*/
+    }
+}

+ 155 - 0
NTERA/Game/GameData/Function/UserDefinedMethodTerm.cs

@@ -0,0 +1,155 @@
+using System;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.GameProc;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameData.Function
+{
+	internal abstract class SuperUserDefinedMethodTerm : IOperandTerm
+	{
+		protected SuperUserDefinedMethodTerm(Type returnType)
+			: base(returnType)
+		{
+		}
+		public abstract UserDefinedFunctionArgument Argument { get;}
+		public abstract CalledFunction Call { get; }
+		public override long GetIntValue(ExpressionMediator exm)
+		{
+			SingleTerm term = exm.Process.GetValue(this);
+			if (term == null)
+				return 0;
+			return term.Int;
+		}
+		public override string GetStrValue(ExpressionMediator exm, bool translate=false)
+		{
+			SingleTerm term = exm.Process.GetValue(this, translate);
+			if (term == null)
+				return "";
+			return term.Str;
+		}
+		public override SingleTerm GetValue(ExpressionMediator exm, bool tryTranslate =false)
+		{
+			SingleTerm term = exm.Process.GetValue(this);
+			if (term == null)
+			{
+				if (GetOperandType() == typeof(Int64))
+					return new SingleTerm(0);
+				return new SingleTerm("");
+			}
+			return term;
+		}
+	}
+
+	internal sealed class UserDefinedMethodTerm : SuperUserDefinedMethodTerm
+	{
+		
+		/// <summary>
+		/// エラーならnullを返す。
+		/// </summary>
+		public static UserDefinedMethodTerm Create(FunctionLabelLine targetLabel, IOperandTerm[] srcArgs, out string errMes)
+		{
+			CalledFunction call = CalledFunction.CreateCalledFunctionMethod(targetLabel, targetLabel.LabelName);
+			UserDefinedFunctionArgument arg = call.ConvertArg(srcArgs, out errMes);
+			if (arg == null)
+				return null;
+			return new UserDefinedMethodTerm(arg, call.TopLabel.MethodType, call);
+		}
+
+		private UserDefinedMethodTerm(UserDefinedFunctionArgument arg, Type returnType, CalledFunction call)
+			: base(returnType)
+		{
+			argment = arg;
+			called = call;
+		}
+		public override UserDefinedFunctionArgument Argument => argment;
+		public override CalledFunction Call => called;
+		private readonly UserDefinedFunctionArgument argment;
+		private readonly CalledFunction called;
+
+		public override IOperandTerm Restructure(ExpressionMediator exm, bool tryTranslate=false)
+		{
+			Argument.Restructure(exm);
+			return this;
+		}
+
+
+		
+	}
+	internal sealed class UserDefinedRefMethodTerm : SuperUserDefinedMethodTerm
+	{
+		public UserDefinedRefMethodTerm(UserDefinedRefMethod reffunc, IOperandTerm[] srcArgs)
+			: base(reffunc.RetType)
+		{
+			this.srcArgs = srcArgs;
+			this.reffunc = reffunc;
+		}
+		IOperandTerm[] srcArgs;
+		readonly UserDefinedRefMethod reffunc;
+		public override UserDefinedFunctionArgument Argument
+		{
+			get
+			{
+				if (reffunc.CalledFunction == null)
+					throw new CodeEE("何も参照していない関数参照" + reffunc.Name + "を呼び出しました");
+				string errMes;
+				UserDefinedFunctionArgument arg = reffunc.CalledFunction.ConvertArg(srcArgs, out errMes);
+				if (arg == null)
+					throw new CodeEE(errMes);
+				return arg;
+			}
+		}
+		public override CalledFunction Call
+		{
+			get
+			{
+				if (reffunc.CalledFunction == null)
+					throw new CodeEE("何も参照していない関数参照" + reffunc .Name+ "を呼び出しました");
+				return reffunc.CalledFunction;
+			}
+		}
+
+		public override IOperandTerm Restructure(ExpressionMediator exm, bool tryTranslate=false)
+		{
+			for (int i = 0; i < srcArgs.Length; i++)
+			{
+				if ((reffunc.ArgTypeList[i] & UserDifinedFunctionDataArgType.__Ref) == UserDifinedFunctionDataArgType.__Ref)
+					srcArgs[i].Restructure(exm);
+				else
+					srcArgs[i] = srcArgs[i].Restructure(exm);
+			}
+			return this;
+		}
+
+
+	}
+
+	internal sealed class UserDefinedRefMethodNoArgTerm : SuperUserDefinedMethodTerm
+	{
+		public UserDefinedRefMethodNoArgTerm(UserDefinedRefMethod reffunc)
+			: base(reffunc.RetType)
+		{
+			this.reffunc = reffunc;
+		}
+		readonly UserDefinedRefMethod reffunc;
+		public override UserDefinedFunctionArgument Argument => throw new CodeEE("引数のない関数参照" + reffunc.Name + "を呼び出しました");
+
+		public override CalledFunction Call => throw new CodeEE("引数のない関数参照" + reffunc.Name + "を呼び出しました");
+
+		public string GetRefName()
+		{
+			if (reffunc.CalledFunction == null)
+				return "";
+			return reffunc.CalledFunction.TopLabel.LabelName;
+		}
+		public override long GetIntValue(ExpressionMediator exm)
+		{ throw new CodeEE("引数のない関数参照" + reffunc.Name + "を呼び出しました"); }
+		public override string GetStrValue(ExpressionMediator exm, bool translate=false)
+		{ throw new CodeEE("引数のない関数参照" + reffunc.Name + "を呼び出しました"); }
+		public override SingleTerm GetValue(ExpressionMediator exm, bool tryTranslate =false)
+		{ throw new CodeEE("引数のない関数参照" + reffunc.Name + "を呼び出しました"); }
+		public override IOperandTerm Restructure(ExpressionMediator exm, bool tryTranslate=false)
+		{
+			return this;
+		}
+	}
+}

+ 89 - 0
NTERA/Game/GameData/Function/UserDefinedRefMethod.cs

@@ -0,0 +1,89 @@
+using System;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.GameProc;
+
+namespace MinorShift.Emuera.GameData.Function
+{
+	internal sealed class UserDefinedRefMethod
+	{
+		public CalledFunction CalledFunction { get; private set; }
+		public string Name { get; private set; }
+		public Type RetType { get; private set; }
+		public UserDifinedFunctionDataArgType[] ArgTypeList { get; private set; }
+
+		internal static UserDefinedRefMethod Create(UserDefinedFunctionData funcData)
+		{
+			UserDefinedRefMethod ret = new UserDefinedRefMethod();
+			ret.Name = funcData.Name;
+			if (funcData.TypeIsStr)
+				ret.RetType = typeof(string);
+			else
+				ret.RetType = typeof(Int64);
+			ret.ArgTypeList = funcData.ArgList;
+			return ret;
+		}
+
+		/// <summary>
+		/// 戻り値と引数の数・型の完全一致が必要
+		/// </summary>
+		/// <param name="call"></param>
+		/// <returns>一致ならtrue</returns>
+		internal bool MatchType(CalledFunction call)
+		{
+			FunctionLabelLine label = call.TopLabel;
+			if (label.IsError)
+				return false;
+			if (RetType != label.MethodType)
+				return false;
+			if (ArgTypeList.Length != label.Arg.Length)
+				return false;
+			for (int i = 0; i < ArgTypeList.Length; i++)
+			{
+				VariableToken vToken = label.Arg[i].Identifier;
+				if (vToken.IsReference)
+				{
+					UserDifinedFunctionDataArgType type = UserDifinedFunctionDataArgType.__Ref;
+					type += vToken.Dimension;
+					if (vToken.IsInteger)
+						type |= UserDifinedFunctionDataArgType.Int;
+					else
+						type |= UserDifinedFunctionDataArgType.Str;
+					if (ArgTypeList[i] != type)
+						return false;
+				}
+				else
+				{
+					if (vToken.IsInteger && ArgTypeList[i] !=  UserDifinedFunctionDataArgType.Int)
+						return false;
+					if (vToken.IsString && ArgTypeList[i] != UserDifinedFunctionDataArgType.Str)
+						return false;
+				}
+			}
+			return true;
+		}
+
+		/// <summary>
+		/// 戻り値と引数の数・型の完全一致が必要
+		/// </summary>
+		/// <param name="rother"></param>
+		/// <returns>一致ならtrue</returns>
+		internal bool MatchType(UserDefinedRefMethod rother)
+		{
+			if (RetType != rother.RetType)
+				return false;
+			if (ArgTypeList.Length != rother.ArgTypeList.Length)
+				return false;
+			for (int i = 0; i < ArgTypeList.Length; i++)
+			{
+				if (ArgTypeList[i] != rother.ArgTypeList[i])
+					return false;
+			}
+			return true;
+		}
+
+		internal void SetReference(CalledFunction call)
+		{
+			CalledFunction = call;
+		}
+	}
+}

+ 182 - 0
NTERA/Game/GameData/GameBase.cs

@@ -0,0 +1,182 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameData
+{
+	internal sealed class GameBase
+	{
+		public string ScriptAutherName = "";
+		public string ScriptDetail = "";//詳細な説明
+		public string ScriptYear = "";
+		public string ScriptTitle = "";
+		public Int64 ScriptUniqueCode;
+		//1.713 訂正。eramakerのバージョンの初期値は1000ではなく0だった
+		public Int64 ScriptVersion;//1000;
+		//1.713 上の変更とあわせて。セーブデータのバージョンが1000であり、現在のバージョンが未定義である場合、セーブデータのバージョンを同じとみなす
+		public bool ScriptVersionDefined;
+		public Int64 ScriptCompatibleMinVersion = -1;
+        public string Compatible_EmueraVer = "0.000.0.0";
+
+		//1.727 追加。Form.Text
+		public string ScriptWindowTitle;
+		public string ScriptVersionText
+		{
+			get
+			{
+				StringBuilder versionStr = new StringBuilder();
+				versionStr.Append((ScriptVersion / 1000).ToString());
+				versionStr.Append(".");
+				if ((ScriptVersion % 10) != 0)
+					versionStr.Append((ScriptVersion % 1000).ToString("000"));
+				else
+					versionStr.Append((ScriptVersion % 1000 / 10).ToString("00"));
+				return versionStr.ToString();
+			}
+		}
+		public bool UniqueCodeEqualTo(Int64 target)
+		{
+			//1804 UniqueCode Int64への拡張に伴い修正
+			if (target == 0L)
+				return true;
+			return target == ScriptUniqueCode;
+		}
+
+		public bool CheckVersion(Int64 target)
+		{
+			if (!ScriptVersionDefined && target != 1000)
+				return true;
+			if (ScriptCompatibleMinVersion <= target)
+				return true;
+			return ScriptVersion == target;
+		}
+
+		public Int64 DefaultCharacter = -1;
+		public Int64 DefaultNoItem;
+
+		private bool tryatoi(string str, out Int64 i)
+		{
+			if (Int64.TryParse(str, out i))
+				return true;
+			StringStream st = new StringStream(str);
+			StringBuilder sb = new StringBuilder(str.Length);
+			while (true)
+			{
+				if (st.EOS)
+					break;
+				if (!char.IsNumber(st.Current))
+					break;
+				sb.Append(st.Current);
+				st.ShiftNext();
+			}
+			if (sb.Length > 0)
+				if (Int64.TryParse(sb.ToString(), out i))
+					return true;
+			return false;
+		}
+
+		public bool LoadGameBaseCsv(string basePath)
+		{
+            if (!File.Exists(basePath))
+            {
+                return true;
+            }
+			ScriptPosition pos = null;
+			EraStreamReader eReader = new EraStreamReader(false);
+			if (!eReader.Open(basePath))
+			{
+				//output.PrintLine(eReader.Filename + "のオープンに失敗しました");
+				return true;
+			}
+			try
+			{
+				StringStream st = null;
+				while ((st = eReader.ReadEnabledLine()) != null)
+				{
+					string[] tokens = st.Substring().Split(',');
+					if (tokens.Length < 2)
+						continue;
+					string param = tokens[1].Trim();
+					pos = new ScriptPosition(eReader.Filename, eReader.LineNo, st.RowString);
+					switch (tokens[0])
+					{
+						case "コード":
+							if (tryatoi(tokens[1], out ScriptUniqueCode))
+							{
+								if (ScriptUniqueCode == 0L)
+									ParserMediator.Warn("コード:0のセーブデータはいかなるコードのスクリプトからも読めるデータとして扱われます", pos, 0);
+							}							
+							break;
+						case "バージョン":
+							ScriptVersionDefined = tryatoi(tokens[1], out ScriptVersion);
+							break;
+						case "バージョン違い認める":
+							tryatoi(tokens[1], out ScriptCompatibleMinVersion);
+							break;
+						case "最初からいるキャラ":
+							tryatoi(tokens[1], out DefaultCharacter);
+							break;
+						case "アイテムなし":
+							tryatoi(tokens[1], out DefaultNoItem);
+							break;
+						case "タイトル":
+							ScriptTitle = tokens[1];
+							break;
+						case "作者":
+							ScriptAutherName = tokens[1];
+							break;
+						case "製作年":
+							ScriptYear = tokens[1];
+							break;
+						case "追加情報":
+							ScriptDetail = tokens[1];
+							break;
+						case "ウィンドウタイトル":
+							ScriptWindowTitle = tokens[1];
+							break;
+							
+                        case "動作に必要なEmueraのバージョン":
+                            Compatible_EmueraVer = tokens[1];
+                            if (!Regex.IsMatch(Compatible_EmueraVer, @"^\d+\.\d+\.\d+\.\d+$"))
+                            {
+                                ParserMediator.Warn("バージョン指定を読み取れなかったので処理を省略します", pos, 0);
+                                break;
+                            }
+                            Version curerntVersion = new Version(GlobalStatic.MainWindow.InternalEmueraVer);
+                            Version targetVersoin = new Version(Compatible_EmueraVer);
+                            if (curerntVersion < targetVersoin)
+                            {
+                                ParserMediator.Warn("このバリアント動作させるにはVer. " + GlobalStatic.MainWindow.EmueraVerText + "以降のバージョンのEmueraが必要です", pos, 2);
+                                return false;
+                            }
+                            break;
+					}
+				}
+			}
+			catch
+			{
+                ParserMediator.Warn("GAMEBASE.CSVの読み込み中にエラーが発生したため、読みこみを中断します", pos, 1);
+				return true;
+			}
+			finally
+			{
+				eReader.Close();
+			}
+			if (ScriptWindowTitle == null)
+			{
+				if (string.IsNullOrEmpty(ScriptTitle))
+					ScriptWindowTitle = "Emuera";
+				else
+					ScriptWindowTitle = ScriptTitle + " " + ScriptVersionText;
+			}
+			return true;
+		}
+	}
+
+
+
+
+
+}

+ 672 - 0
NTERA/Game/GameData/IdentifierDictionary.cs

@@ -0,0 +1,672 @@
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using MinorShift.Emuera.GameData;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.GameData.Function;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.GameProc;
+using MinorShift.Emuera.GameProc.Function;
+using MinorShift.Emuera.Sub;
+using MinorShift._Library;
+
+namespace MinorShift.Emuera
+{
+	//1756 新設。
+	//また、使用されている名前を記憶し衝突を検出する。
+	internal sealed class IdentifierDictionary
+	{
+		private enum DefinedNameType
+		{
+			None = 0,
+			Reserved,
+			SystemVariable,
+			SystemMethod,
+			SystemInstrument,
+			//UserIdentifier,
+			UserGlobalVariable,
+			UserMacro,
+			UserRefMethod,
+			NameSpace
+		}
+		static readonly char[] badSymbolAsIdentifier = {
+			'+', '-', '*', '/', '%', '=', '!', '<', '>', '|', '&', '^', '~',
+			' ', ' ', '\t' ,
+			'\"','(', ')', '{', '}', '[', ']', ',', '.', ':',
+			'\\', '@', '$', '#', '?', ';', '\''
+			//'_'はOK
+		};
+		static readonly Regex regexCom = new Regex("^COM[0-9]+$");
+		static readonly Regex regexComAble = new Regex("^COM_ABLE[0-9]+$");
+		static readonly Regex regexAblup = new Regex("^ABLUP[0-9]+$");
+		#region static
+		
+		public static bool IsEventLabelName(string labelName)
+		{
+			switch (labelName)
+			{
+				case "EVENTFIRST":
+				case "EVENTTRAIN":
+				case "EVENTSHOP":
+				case "EVENTBUY":
+				case "EVENTCOM":
+				case "EVENTTURNEND":
+				case "EVENTCOMEND":
+				case "EVENTEND":
+				case "EVENTLOAD":
+					return true;
+			}
+			return false;
+		}
+		public static bool IsSystemLabelName(string labelName)
+		{
+			switch (labelName)
+			{
+				case "EVENTFIRST":
+				case "EVENTTRAIN":
+				case "EVENTSHOP":
+				case "EVENTBUY":
+				case "EVENTCOM":
+				case "EVENTTURNEND":
+				case "EVENTCOMEND":
+				case "EVENTEND":
+				case "SHOW_STATUS":
+				case "SHOW_USERCOM":
+				case "USERCOM":
+				case "SOURCE_CHECK":
+				case "CALLTRAINEND":
+				case "SHOW_JUEL":
+				case "SHOW_ABLUP_SELECT":
+				case "USERABLUP":
+				case "SHOW_SHOP":
+				case "SAVEINFO":
+				case "USERSHOP":
+
+				case "EVENTLOAD":
+				case "TITLE_LOADGAME":
+				case "SYSTEM_AUTOSAVE":
+				case "SYSTEM_TITLE":
+				case "SYSTEM_LOADEND":
+					return true;
+			}
+
+			if (labelName.StartsWith("COM"))
+			{
+				if (regexCom.IsMatch(labelName))
+					return true;
+				if (regexComAble.IsMatch(labelName))
+					return true;
+			}
+			if (labelName.StartsWith("ABLUP"))
+				if (regexAblup.IsMatch(labelName))
+					return true;
+			return false;
+		}
+		#endregion
+
+
+		Dictionary<string, DefinedNameType> nameDic = new Dictionary<string, DefinedNameType>();
+
+		List<string> privateDimList = new List<string>();
+		List<string> disableList = new List<string>();
+		//Dictionary<string, VariableToken> userDefinedVarDic = new Dictionary<string, VariableToken>();
+
+		VariableData varData;
+		Dictionary<string, VariableToken> varTokenDic;
+		Dictionary<string, VariableLocal> localvarTokenDic;
+		Dictionary<string, FunctionIdentifier> instructionDic;
+		Dictionary<string, FunctionMethod> methodDic;
+		Dictionary<string, UserDefinedRefMethod> refmethodDic;
+		public List<UserDefinedCharaVariableToken> CharaDimList = new List<UserDefinedCharaVariableToken>();
+		#region initialize
+		public IdentifierDictionary(VariableData varData)
+		{
+			this.varData = varData;
+			nameDic.Clear();
+			//予約語を登録。式中に登場すると構文解析が崩壊する名前群。
+			//ただしeramaker用スクリプトなら特に気にすることはない。式中に出てこない単語も同様。
+			nameDic.Add("IS", DefinedNameType.Reserved);
+			nameDic.Add("TO", DefinedNameType.Reserved);
+			nameDic.Add("INT", DefinedNameType.Reserved);
+			nameDic.Add("STR", DefinedNameType.Reserved);
+			nameDic.Add("REFFUNC", DefinedNameType.Reserved);
+			nameDic.Add("STATIC", DefinedNameType.Reserved);
+			nameDic.Add("DYNAMIC", DefinedNameType.Reserved);
+			nameDic.Add("GLOBAL", DefinedNameType.Reserved);
+			nameDic.Add("PRIVATE", DefinedNameType.Reserved);
+			nameDic.Add("SAVEDATA", DefinedNameType.Reserved);
+			nameDic.Add("CHARADATA", DefinedNameType.Reserved);//CHARDATAから変更
+			nameDic.Add("REF", DefinedNameType.Reserved);
+			nameDic.Add("__DEBUG__", DefinedNameType.Reserved);
+			nameDic.Add("__SKIP__", DefinedNameType.Reserved);
+			nameDic.Add("_", DefinedNameType.Reserved);
+			instructionDic = FunctionIdentifier.GetInstructionNameDic();
+
+			varTokenDic = varData.GetVarTokenDicClone();
+			localvarTokenDic = varData.GetLocalvarTokenDic();
+			methodDic = FunctionMethodCreator.GetMethodList();
+			refmethodDic = new Dictionary<string, UserDefinedRefMethod>();
+
+			foreach(KeyValuePair<string, FunctionMethod> pair in methodDic)
+			{
+				nameDic.Add(pair.Key, DefinedNameType.SystemMethod);
+			}
+
+			foreach (KeyValuePair<string, VariableToken> pair in varTokenDic)
+			{
+				//RANDが衝突している
+				//1808a3 GLOBAL、PRIVATEも
+				//1808beta009 REFも
+				if (!nameDic.ContainsKey(pair.Key)) 
+					nameDic.Add(pair.Key, DefinedNameType.SystemVariable);
+			}
+
+			foreach (KeyValuePair<string, VariableLocal> pair in localvarTokenDic)
+			{
+				nameDic.Add(pair.Key, DefinedNameType.SystemVariable);
+			}
+
+			foreach (KeyValuePair<string, FunctionIdentifier> pair in instructionDic)
+			{
+				//Methodと被る
+				//1808a3 SAVEDATAも
+				if (!nameDic.ContainsKey(pair.Key))
+					nameDic.Add(pair.Key, DefinedNameType.SystemInstrument);
+			}
+		}
+		
+		//public void SetSystemInstrumentName(List<string> names)
+		//{
+		//}
+		
+		public void CheckUserLabelName(ref string errMes, ref int warnLevel, bool isFunction, string labelName)
+		{
+			if (labelName.Length == 0)
+			{
+				errMes = "Label name is missing";
+				warnLevel = 2;
+				return;
+			}
+			//1.721 記号をサポートしない方向に変更
+			if (labelName.IndexOfAny(badSymbolAsIdentifier) >= 0)
+			{
+				errMes = "Label name " + labelName + " has symbols other than \"_\" included";
+				warnLevel = 1;
+				return;
+			}
+			if (char.IsDigit(labelName[0]) && (labelName[0].ToString()).Length == LangManager.GetStrlenLang(labelName[0].ToString()))
+			{
+                errMes = "Label name " + labelName + " begins with a half-width digit";
+				warnLevel = 0;
+				return;
+			}
+			if (!isFunction || !Config.WarnFunctionOverloading)
+				return;
+			if (!nameDic.ContainsKey(labelName))
+				return;
+
+			if (nameDic.ContainsKey(labelName))
+			{
+				switch (nameDic[labelName])
+				{
+					case DefinedNameType.Reserved:
+						if (Config.AllowFunctionOverloading)
+						{
+							errMes = "Function name " + labelName + " conflicts with Emuera\'s reserved word.\n" + "There is a risk of interfering with Emuera exclusive syntax parsing";
+							warnLevel = 1;
+						}
+						else
+						{
+							errMes = "Function name " + labelName + " is a reserved word for Emuera";
+							warnLevel = 2;
+						}
+						break;
+					case DefinedNameType.SystemMethod:
+						if (Config.AllowFunctionOverloading)
+						{
+							errMes = "関数名" + labelName + "はEmueraの式中関数を上書きします";
+							warnLevel = 1;
+						}
+						else
+						{
+							errMes = "関数名" + labelName + "はEmueraの式中関数名として使われています";
+							warnLevel = 2;
+						}
+						break;
+					case DefinedNameType.SystemVariable:
+						errMes = "関数名" + labelName + "はEmueraの変数で使われています";
+						warnLevel = 1;
+						break;
+					case DefinedNameType.SystemInstrument:
+						errMes = "関数名" + labelName + "はEmueraの変数もしくは命令で使われています";
+						warnLevel = 1;
+						break;
+					case DefinedNameType.UserMacro:
+						//字句解析がうまくいっていれば本来あり得ないはず
+						errMes = "関数名" + labelName + "はマクロに使用されています";
+						warnLevel = 2;
+						break;
+					case DefinedNameType.UserRefMethod:
+						errMes = "関数名" + labelName + "は参照型関数の名称に使用されています";
+						warnLevel = 2;
+						break;
+				}
+			}
+		}
+		
+		public void CheckUserVarName(ref string errMes, ref int warnLevel, string varName)
+		{
+			//if (varName.Length == 0)
+			//{
+			//    errMes = "変数名がありません";
+			//    warnLevel = 2;
+			//    return;
+			//}
+			//1.721 記号をサポートしない方向に変更
+			if (varName.IndexOfAny(badSymbolAsIdentifier) >= 0)
+			{
+				errMes = "変数名" + varName + "に\"_\"以外の記号が含まれています";
+				warnLevel = 2;
+				return;
+			}
+			//if (char.IsDigit(varName[0]))
+			//{
+			//    errMes = "変数名" + varName + "が半角数字から始まっています";
+			//    warnLevel = 2;
+			//    return;
+			//}
+
+			if (nameDic.ContainsKey(varName))
+			{
+				switch (nameDic[varName])
+				{
+					case DefinedNameType.Reserved:
+						errMes = "変数名" + varName + "はEmueraの予約語です";
+						warnLevel = 2;
+						break;
+					case DefinedNameType.SystemInstrument:
+					case DefinedNameType.SystemMethod:
+						//代入文が使えなくなるために命令名との衝突は致命的。
+						errMes = "変数名" + varName + "はEmueraの命令名として使われています";
+						warnLevel = 2;
+						break;
+					case DefinedNameType.SystemVariable:
+						errMes = "変数名" + varName + "はEmueraの変数名として使われています";
+						warnLevel = 2;
+						break;
+					case DefinedNameType.UserMacro:
+						errMes = "変数名" + varName + "は既にマクロ名に使用されています";
+						warnLevel = 2;
+						break;
+					case DefinedNameType.UserGlobalVariable:
+						errMes = "変数名" + varName + "はユーザー定義の広域変数名に使用されています";
+						warnLevel = 2;
+						break;
+					case DefinedNameType.UserRefMethod:
+						errMes = "変数名" + varName + "は参照型関数の名称に使用されています";
+						warnLevel = 2;
+						break;
+				}
+			}
+		}
+
+		public void CheckUserMacroName(ref string errMes, ref int warnLevel, string macroName)
+		{
+			if (macroName.IndexOfAny(badSymbolAsIdentifier) >= 0)
+			{
+				errMes = "マクロ名" + macroName + "に\"_\"以外の記号が含まれています";
+				warnLevel = 2;
+				return;
+			}
+			if (nameDic.ContainsKey(macroName))
+			{
+				switch (nameDic[macroName])
+				{
+					case DefinedNameType.Reserved:
+						errMes = "マクロ名" + macroName + "はEmueraの予約語です";
+						warnLevel = 2;
+						break;
+					case DefinedNameType.SystemInstrument:
+					case DefinedNameType.SystemMethod:
+						//命令名を上書きした時が面倒なのでとりあえず許可しない
+						errMes = "マクロ名" + macroName + "はEmueraの命令名として使われています";
+						warnLevel = 2;
+						break;
+					case DefinedNameType.SystemVariable:
+						//別に上書きしてもいいがとりあえず許可しないでおく。いずれ解放するかもしれない
+						errMes = "マクロ名" + macroName + "はEmueraの変数名として使われています";
+						warnLevel = 2;
+						break;
+					case DefinedNameType.UserMacro:
+						errMes = "マクロ名" + macroName + "は既にマクロ名に使用されています";
+						warnLevel = 2;
+						break;
+					case DefinedNameType.UserGlobalVariable:
+						errMes = "マクロ名" + macroName + "はユーザー定義の広域変数名に使用されています";
+						warnLevel = 2;
+						break;
+					case DefinedNameType.UserRefMethod:
+						errMes = "マクロ名" + macroName + "は参照型関数の名称に使用されています";
+						warnLevel = 2;
+						break;
+				}
+			}
+		}
+
+		public void CheckUserPrivateVarName(ref string errMes, ref int warnLevel, string varName)
+		{
+			if (varName.Length == 0)
+			{
+				errMes = "変数名がありません";
+				warnLevel = 2;
+				return;
+			}
+			//1.721 記号をサポートしない方向に変更
+			if (varName.IndexOfAny(badSymbolAsIdentifier) >= 0)
+			{
+				errMes = "変数名" + varName + "に\"_\"以外の記号が含まれています";
+				warnLevel = 2;
+				return;
+			}
+			if (char.IsDigit(varName[0]))
+			{
+				errMes = "変数名" + varName + "が半角数字から始まっています";
+				warnLevel = 2;
+				return;
+			}
+			if(nameDic.ContainsKey(varName))
+			{
+				switch(nameDic[varName])
+				{
+					case DefinedNameType.Reserved:
+						errMes = "変数名" + varName + "はEmueraの予約語です";
+						warnLevel = 2;
+						return;
+					case DefinedNameType.SystemInstrument:
+					case DefinedNameType.SystemMethod:
+						//代入文が使えなくなるために命令名との衝突は致命的。
+						errMes = "変数名" + varName + "はEmueraの命令名として使われています";
+						warnLevel = 2;
+						return;
+					case DefinedNameType.SystemVariable:
+						//システム変数の上書きは不可
+                        errMes = "変数名" + varName + "はEmueraの変数名として使われています";
+                        warnLevel = 2;
+						break;
+					case DefinedNameType.UserMacro:
+						//字句解析がうまくいっていれば本来あり得ないはず
+						errMes = "変数名" + varName + "はマクロに使用されています";
+						warnLevel = 2;
+						break;
+					case DefinedNameType.UserGlobalVariable:
+						//広域変数の上書きは禁止しておく
+						errMes = "変数名" + varName + "はユーザー定義の広域変数名に使用されています";
+						warnLevel = 2;
+						break;
+					case DefinedNameType.UserRefMethod:
+						errMes = "変数名" + varName + "は参照型関数の名称に使用されています";
+						warnLevel = 2;
+						break;
+                }
+			}
+			privateDimList.Add(varName);
+		}
+		#endregion
+
+		#region header.erb
+		//1807 ErbLoaderに移動
+		Dictionary<string, DefineMacro> macroDic = new Dictionary<string, DefineMacro>();
+
+		internal void AddUseDefinedVariable(VariableToken var)
+		{
+			varTokenDic.Add(var.Name, var);
+			if (var.IsCharacterData)
+			{
+
+			}
+			nameDic.Add(var.Name, DefinedNameType.UserGlobalVariable);
+		}
+		internal void AddMacro(DefineMacro mac)
+		{
+			nameDic.Add(mac.Keyword, DefinedNameType.UserMacro);
+			macroDic.Add(mac.Keyword, mac);
+		}
+		internal void AddRefMethod(UserDefinedRefMethod refm)
+		{
+			refmethodDic.Add(refm.Name, refm);
+			nameDic.Add(refm.Name, DefinedNameType.UserRefMethod);
+		}
+		#endregion
+
+		#region get
+
+		public bool UseMacro()
+		{
+			return macroDic.Count > 0;
+		}
+
+		public DefineMacro GetMacro(string key)
+		{
+			if (Config.ICVariable)
+				key = key.ToUpper();
+			if (macroDic.ContainsKey(key))
+				return macroDic[key];
+			return null;
+		}
+
+		public VariableToken GetVariableToken(string key, string subKey, bool allowPrivate)
+		{
+			VariableToken ret = null;
+            if (Config.ICVariable)
+                key = key.ToUpper();
+            if (allowPrivate)
+			{
+				LogicalLine line = GlobalStatic.Process.GetScaningLine();
+				if ((line != null) && (line.ParentLabelLine != null))
+				{
+					ret = line.ParentLabelLine.GetPrivateVariable(key);
+					if(ret != null)
+					{
+						if (subKey != null)
+							throw new CodeEE("プライベート変数" + key + "に対して@が使われました");
+						return ret;
+					}
+				}
+			}
+			if (localvarTokenDic.ContainsKey(key))
+			{
+				if (localvarTokenDic[key].IsForbid)
+                {
+					throw new CodeEE("呼び出された変数\"" + key + "\"は設定により使用が禁止されています");
+                }
+				LogicalLine line = GlobalStatic.Process.GetScaningLine();
+				if (string.IsNullOrEmpty(subKey))
+				{
+					//システムの入力待ち中にデバッグコマンドからLOCALを呼んだとき。
+					if ((line == null) || (line.ParentLabelLine == null))
+						throw new CodeEE("実行中の関数が存在しないため" + key + "を取得又は変更できませんでした");
+					subKey = line.ParentLabelLine.LabelName;
+				}
+				else
+				{
+					ParserMediator.Warn("コード中でローカル変数を@付きで呼ぶことは推奨されません(代わりに*.ERHファイルの利用を検討してください)", line, 1, false, false);
+					if (Config.ICFunction)
+						subKey = subKey.ToUpper();
+				}
+                LocalVariableToken retLocal = localvarTokenDic[key].GetExistLocalVariableToken(subKey);
+                if (retLocal == null)
+                    retLocal = localvarTokenDic[key].GetNewLocalVariableToken(subKey, line.ParentLabelLine);
+                return retLocal;
+			}
+			if (varTokenDic.TryGetValue(key, out ret))
+			{
+                //一文字変数の禁止オプションを考えた名残
+                //if (Config.ForbidOneCodeVariable && ret.CanForbid)
+                //    throw new CodeEE("設定によりシステム一文字数値変数の使用が禁止されています(呼び出された変数:" + ret.Name +")");
+                if (ret.IsForbid)
+                {
+					if(!ret.CanForbid)
+						throw new ExeEE("CanForbidでない変数\"" + ret.Name +"\"にIsForbidがついている");
+                    throw new CodeEE("呼び出された変数\"" + ret.Name +"\"は設定により使用が禁止されています");
+                }
+				if (subKey != null)
+					throw new CodeEE("ローカル変数でない変数" + key + "に対して@が使われました");
+                return ret;
+            }
+			if (subKey != null)
+				throw new CodeEE("@の使い方が不正です");
+			return null;
+		}
+
+		public FunctionIdentifier GetFunctionIdentifier(string str)
+		{
+			string key = str;
+			FunctionIdentifier ret = null;
+			if (string.IsNullOrEmpty(key))
+				return null;
+			if (Config.ICFunction)
+				key = key.ToUpper();
+			instructionDic.TryGetValue(key, out ret);
+			return ret;
+		}
+
+		public List<string> GetOverloadedList(LabelDictionary labelDic)
+		{
+			List<string> list = new List<string>();
+			foreach (KeyValuePair<string, FunctionMethod> pair in methodDic)
+			{
+				FunctionLabelLine func = labelDic.GetNonEventLabel(pair.Key);
+				if (func == null)
+					continue;
+				if (!func.IsMethod)
+					continue;
+				list.Add(pair.Key);
+			}
+			return list;
+		}
+
+		public UserDefinedRefMethod GetRefMethod(string codeStr)
+		{
+			if (Config.ICFunction)
+				codeStr = codeStr.ToUpper();
+			if (refmethodDic.ContainsKey(codeStr))
+				return refmethodDic[codeStr];
+			return null;
+		}
+
+		public IOperandTerm GetFunctionMethod(LabelDictionary labelDic, string codeStr, IOperandTerm[] arguments, bool userDefinedOnly)
+		{
+			if (Config.ICFunction)
+				codeStr = codeStr.ToUpper();
+			if (arguments == null)//引数なし、名前のみの探索
+			{
+				if (refmethodDic.ContainsKey(codeStr))
+					return new UserDefinedRefMethodNoArgTerm(refmethodDic[codeStr]);
+				return null;
+			}
+			if ((labelDic != null) && (labelDic.Initialized))
+			{
+				if (refmethodDic.ContainsKey(codeStr))
+					return new UserDefinedRefMethodTerm(refmethodDic[codeStr], arguments);
+				FunctionLabelLine func = labelDic.GetNonEventLabel(codeStr);
+				if (func != null)
+				{
+					if (userDefinedOnly && !func.IsMethod)
+					{
+						throw new CodeEE("#FUNCTIONが指定されていない関数\"@" + func.LabelName + "\"をCALLF系命令で呼び出そうとしました");
+					}
+					if (func.IsMethod)
+					{
+						string errMes;
+						IOperandTerm ret = UserDefinedMethodTerm.Create(func, arguments, out errMes);
+						if(ret == null)
+							throw new CodeEE(errMes);
+						return ret;
+					}
+					//1.721 #FUNCTIONが定義されていない関数は組み込み関数を上書きしない方向に。 PANCTION.ERBのRANDとか。
+					if (!methodDic.ContainsKey(codeStr))
+						throw new CodeEE("Function for which #FUNCTION was not declared (" + func.Position.Filename + " at line :" + func.Position.LineNo + ") has been attempted to be called inside of an expression");
+				}
+			}
+			if (userDefinedOnly)
+				return null;
+			FunctionMethod method = null;
+			if (!methodDic.TryGetValue(codeStr, out method))
+				return null;
+			string errmes = method.CheckArgumentType(codeStr, arguments);
+			if (errmes != null)
+				throw new CodeEE(errmes);
+			return new FunctionMethodTerm(method, arguments);
+		}
+
+		//1756 作成中途
+		//名前リストを元に何がやりたかったのかを推定してCodeEEを投げる
+		public void ThrowException(string str, bool isFunc)
+		{
+			string idStr = str;
+			if(Config.ICFunction || Config.ICVariable) //片方だけなのは互換性用オプションなのでレアケースのはず。対応しない。
+				idStr = idStr.ToUpper();
+			if (disableList.Contains(idStr))
+				throw new CodeEE("\"" + str + "\" is declaring #DISABLE");
+			if (!isFunc && privateDimList.Contains(idStr))
+				throw new CodeEE("Variable \"" + str + "\" is not defined in this function");
+			if (nameDic.ContainsKey(idStr))
+			{
+				DefinedNameType type = nameDic[idStr];
+				switch (type)
+				{
+					case DefinedNameType.Reserved:
+						throw new CodeEE("Emuera\'s reserved word \"" + str + "\" is being used in an illegal way");
+					case DefinedNameType.SystemVariable:
+					case DefinedNameType.UserGlobalVariable:
+						if (isFunc)
+							throw new CodeEE("Variable name \"" + str + "\" is used like a function");
+						break;
+					case DefinedNameType.SystemMethod:
+					case DefinedNameType.UserRefMethod:
+						if (!isFunc)
+							throw new CodeEE("Function name \"" + str + "\" is used like a variable");
+						break;
+					case DefinedNameType.UserMacro:
+						throw new CodeEE("Unexpected macro name: \"" + str + "\"");
+					case DefinedNameType.SystemInstrument:
+						if (isFunc)
+							throw new CodeEE("Instruction name \"" + str + "\" is used like a function");
+						else
+							throw new CodeEE("Instruction name \"" + str + "\" is used like a variable");
+			
+				}
+			}
+			throw new CodeEE("\"" + idStr + "\" cannot be interpreted");
+		}
+		#endregion
+
+        #region util
+        public void resizeLocalVars(string key, string subKey, int newSize)
+        {
+            localvarTokenDic[key].ResizeLocalVariableToken(subKey, newSize);
+        }
+
+        public int getLocalDefaultSize(string key)
+        {
+            return localvarTokenDic[key].GetDefaultSize();
+        }
+
+		public bool getLocalIsForbid(string key)
+		{
+			return localvarTokenDic[key].IsForbid;
+		}
+        public bool getVarTokenIsForbid(string key)
+        {
+            if (localvarTokenDic.ContainsKey(key))
+                return localvarTokenDic[key].IsForbid;
+            VariableToken var = null;
+            varTokenDic.TryGetValue(key, out var);
+            if (var != null)
+                return var.IsForbid;
+            return true;
+        }
+        #endregion
+
+
+	}
+}

+ 173 - 0
NTERA/Game/GameData/ParserMediator.cs

@@ -0,0 +1,173 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text.RegularExpressions;
+using MinorShift.Emuera.GameProc;
+using MinorShift.Emuera.Sub;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera
+{
+	//1756 新設。ParserやLexicalAnalyzerなどが知りたい情報をまとめる
+	//本当は引数として渡すべきなのかもしれないが全てのParserの引数を書きなおすのが面倒なのでstatic
+	internal static class ParserMediator
+	{
+		/// <summary>
+		/// emuera.config等で発生した警告
+		/// Initializeより前に発生する
+		/// </summary>
+		/// <param name="str"></param>
+		/// <param name="?"></param>
+		public static void ConfigWarn(string str, ScriptPosition pos, int level, string stack)
+		{
+			if (level < Config.DisplayWarningLevel && !Program.AnalysisMode)
+				return;
+			warningList.Add(new ParserWarning(str, pos, level, stack));
+		}
+
+		static IConsole console;
+		public static void Initialize(IConsole console)
+		{
+			ParserMediator.console = console;
+		}
+
+		#region Rename
+		public static Dictionary<string, string> RenameDic { get; private set; }
+		//1756 Process.Load.csより移動
+		public static void LoadEraExRenameFile(string filepath)
+		{
+			if (RenameDic != null)
+				RenameDic.Clear();
+			//とにかく辞書を作る。辞書がnullのときは UseRenameFileがNOの時のみ
+			RenameDic = new Dictionary<string, string>();
+			EraStreamReader eReader = new EraStreamReader(false);
+			if ((!File.Exists(filepath)) || (!eReader.Open(filepath)))
+			{
+				return;
+			}
+			string line = null;
+			ScriptPosition pos = null;
+			Regex reg = new Regex(@"\\,", RegexOptions.Compiled);
+			try
+			{
+				while ((line = eReader.ReadLine()) != null)
+				{
+					if (line.Length == 0)
+						continue;
+					if (line.StartsWith(";"))
+						continue;
+					string[] baseTokens = reg.Split(line);
+					if (!baseTokens[baseTokens.Length - 1].Contains(","))
+						continue;
+					string[] last = baseTokens[baseTokens.Length - 1].Split(',');
+					baseTokens[baseTokens.Length - 1] = last[0];
+					string[] tokens = new string[2];
+					tokens[0] = string.Join(",", baseTokens);
+					tokens[1] = last[1];
+					pos = new ScriptPosition(eReader.Filename, eReader.LineNo, line);
+					//右がERB中の表記、左が変換先になる。
+					string value = tokens[0].Trim();
+					string key = string.Format("[[{0}]]", tokens[1].Trim());
+					RenameDic[key] = value;
+					pos = null;
+				}
+			}
+			catch (Exception e)
+			{
+				if (pos != null)
+					throw new CodeEE(e.Message, pos);
+				else
+					throw new CodeEE(e.Message);
+
+			}
+			finally
+			{
+				eReader.Close();
+			}
+		}
+		#endregion
+
+
+		public static void Warn(string str, ScriptPosition pos, int level)
+		{
+			Warn(str, pos, level, null);
+		}
+
+		public static void Warn(string str, ScriptPosition pos, int level, string stack)
+		{
+			if (level < Config.DisplayWarningLevel && !Program.AnalysisMode)
+				return;
+			if (console != null && !console.RunERBFromMemory)
+				warningList.Add(new ParserWarning(str, pos, level, stack));
+		}
+
+		/// <summary>
+		/// Parser中での警告出力
+		/// </summary>
+		/// <param name="str"></param>
+		/// <param name="line"></param>
+		/// <param name="level">警告レベル.0:軽微なミス.1:無視できる行.2:行が実行されなければ無害.3:致命的</param>
+		public static void Warn(string str, LogicalLine line, int level, bool isError, bool isBackComp)
+		{
+            Warn(str, line, level, isError, isBackComp, null);
+		}
+
+        public static void Warn(string str, LogicalLine line, int level, bool isError, bool isBackComp, string stack)
+        {
+            if (isError)
+            {
+                line.IsError = true;
+                line.ErrMes = str;
+            }
+            if (level < Config.DisplayWarningLevel && !Program.AnalysisMode)
+                return;
+            if (isBackComp && !Config.WarnBackCompatibility)
+                return;
+            if (console != null && !console.RunERBFromMemory)
+                warningList.Add(new ParserWarning(str, line.Position, level, stack));
+            //				console.PrintWarning(str, line.Position, level);
+        }
+        
+        private static List<ParserWarning> warningList = new List<ParserWarning>();
+
+		public static bool HasWarning => warningList.Count > 0;
+
+		public static void ClearWarningList()
+		{
+			warningList.Clear();
+		}
+
+		public static void FlushWarningList()
+		{
+			for (int i = 0; i < warningList.Count; i++)
+			{
+				ParserWarning warning = warningList[i];
+				console.PrintWarning(warning.WarningMes, warning.WarningPos, warning.WarningLevel);
+                if (warning.StackTrace != null)
+                {
+                    string[] stacks = warning.StackTrace.Split('\n');
+                    for (int j = 0; j < stacks.Length; j++)
+                    {
+						console.PrintSystemLine(stacks[j]);
+                    }
+                }
+            }
+			warningList.Clear();
+		}
+
+		private class ParserWarning
+		{
+			public ParserWarning(string mes, ScriptPosition pos, int level, string stackTrace)
+			{
+				WarningMes = mes;
+				WarningPos = pos;
+				WarningLevel = level;
+                StackTrace = stackTrace;
+			}
+			public string WarningMes;
+			public ScriptPosition WarningPos;
+			public int WarningLevel;
+            public string StackTrace;
+		}
+	}
+}

+ 297 - 0
NTERA/Game/GameData/StrForm.cs

@@ -0,0 +1,297 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.GameData.Function;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.Sub;
+using MinorShift._Library;
+
+namespace MinorShift.Emuera.GameData
+{
+	internal sealed class StrForm
+	{
+		private StrForm() { }
+		string[] strs;//terms.Length + 1
+		IOperandTerm[] terms;
+
+		#region static
+		static FormattedStringMethod formatCurlyBrace;
+		static FormattedStringMethod formatPercent;
+		static FormattedStringMethod formatYenAt;
+		static FunctionMethodTerm NameTarget;// "***"
+		static FunctionMethodTerm CallnameMaster;// "+++"
+		static FunctionMethodTerm CallnamePlayer;// "==="
+		static FunctionMethodTerm NameAssi;// "///"
+		static FunctionMethodTerm CallnameTarget;// "$$$"
+		public static void Initialize()
+		{
+			formatCurlyBrace = new FormatCurlyBrace();
+			formatPercent = new FormatPercent();
+			formatYenAt = new FormatYenAt();
+			VariableToken nameID = GlobalStatic.VariableData.GetSystemVariableToken("NAME");
+			VariableToken callnameID = GlobalStatic.VariableData.GetSystemVariableToken("CALLNAME");
+			IOperandTerm[] zeroArg = { new SingleTerm(0) };
+			VariableTerm target = new VariableTerm(GlobalStatic.VariableData.GetSystemVariableToken("TARGET"), zeroArg);
+			VariableTerm master = new VariableTerm(GlobalStatic.VariableData.GetSystemVariableToken("MASTER"), zeroArg);
+			VariableTerm player = new VariableTerm(GlobalStatic.VariableData.GetSystemVariableToken("PLAYER"), zeroArg);
+			VariableTerm assi = new VariableTerm(GlobalStatic.VariableData.GetSystemVariableToken("ASSI"), zeroArg);
+
+			VariableTerm nametarget = new VariableTerm(nameID, new IOperandTerm[] { target });
+			VariableTerm callnamemaster = new VariableTerm(callnameID, new IOperandTerm[] { master });
+			VariableTerm callnameplayer = new VariableTerm(callnameID, new IOperandTerm[] { player });
+			VariableTerm nameassi = new VariableTerm(nameID, new IOperandTerm[] { assi });
+			VariableTerm callnametarget = new VariableTerm(callnameID, new IOperandTerm[] { target });
+			NameTarget = new FunctionMethodTerm(formatPercent, new IOperandTerm[] { nametarget, null, null });
+            CallnameMaster = new FunctionMethodTerm(formatPercent, new IOperandTerm[] { callnamemaster, null, null });
+            CallnamePlayer = new FunctionMethodTerm(formatPercent, new IOperandTerm[] { callnameplayer, null, null });
+            NameAssi = new FunctionMethodTerm(formatPercent, new IOperandTerm[] { nameassi, null, null });
+            CallnameTarget = new FunctionMethodTerm(formatPercent, new IOperandTerm[] { callnametarget, null, null });
+		}
+
+		public static StrForm FromWordToken(StrFormWord wt)
+		{
+			StrForm ret = new StrForm();
+			ret.strs = wt.Strs;
+			IOperandTerm[] termArray = new IOperandTerm[wt.SubWords.Length];
+			for (int i = 0; i < wt.SubWords.Length; i++)
+			{
+				SubWord SWT = wt.SubWords[i];
+				TripleSymbolSubWord tSymbol = SWT as TripleSymbolSubWord;
+				if (tSymbol != null)
+				{
+					switch (tSymbol.Code)
+					{
+						case '*':
+							termArray[i] = NameTarget;
+							continue;
+						case '+':
+							termArray[i] = CallnameMaster;
+							continue;
+						case '=':
+							termArray[i] = CallnamePlayer;
+							continue;
+						case '/':
+							termArray[i] = NameAssi;
+							continue;
+						case '$':
+							termArray[i] = CallnameTarget;
+							continue;
+					}
+					throw new ExeEE("何かおかしい");
+				}
+                WordCollection wc = null;
+				IOperandTerm operand = null;
+				YenAtSubWord yenat = SWT as YenAtSubWord;
+				if (yenat != null)
+				{
+					wc = yenat.Words;
+                    if (wc != null)
+                    {
+                        operand = ExpressionParser.ReduceIntegerTerm(wc, TermEndWith.EoL);
+                        if (!wc.EOL)
+                            throw new CodeEE("三項演算子\\@の第一オペランドが異常です");
+                    }
+                    else
+                        operand = new SingleTerm(0);
+					IOperandTerm left = new StrFormTerm(FromWordToken(yenat.Left));
+					IOperandTerm right = null;
+					if (yenat.Right == null)
+						right = new SingleTerm("");
+					else
+						right = new StrFormTerm(FromWordToken(yenat.Right));
+					termArray[i] = new FunctionMethodTerm(formatYenAt, new[] { operand, left, right });
+					continue;
+				}
+                wc = SWT.Words;
+                operand = ExpressionParser.ReduceExpressionTerm(wc, TermEndWith.Comma);
+                if (operand == null)
+                {
+	                if (SWT is CurlyBraceSubWord)
+                        throw new CodeEE("{}の中に式が存在しません");
+	                throw new CodeEE("%%の中に式が存在しません");
+                }
+                IOperandTerm second = null;
+				SingleTerm third = null;
+				wc.ShiftNext();
+                if (!wc.EOL)
+                {
+                    second = ExpressionParser.ReduceIntegerTerm(wc, TermEndWith.Comma);
+
+                    wc.ShiftNext();
+                    if (!wc.EOL)
+                    {
+                        IdentifierWord id = wc.Current as IdentifierWord;
+                        if (id == null)
+                            throw new CodeEE("','の後にRIGHT又はLEFTがありません");
+                        if (string.Equals(id.Code, "LEFT", Config.SCVariable))//標準RIGHT
+                            third = new SingleTerm(1);
+                        else if (!string.Equals(id.Code, "RIGHT", Config.SCVariable))
+                            throw new CodeEE("','の後にRIGHT又はLEFT以外の単語があります");
+                        wc.ShiftNext();
+                    }
+                    if (!wc.EOL)
+                        throw new CodeEE("RIGHT又はLEFTの後に余分な文字があります");
+                }
+				if (SWT is CurlyBraceSubWord)
+				{
+					if (operand.GetOperandType() != typeof(Int64))
+						throw new CodeEE("{}の中の式が数式ではありません");
+					termArray[i] = new FunctionMethodTerm(formatCurlyBrace, new[] { operand, second, third });
+					continue;
+				}
+				if (operand.GetOperandType() != typeof(string))
+					throw new CodeEE("%%の中の式が文字列式ではありません");
+				termArray[i] = new FunctionMethodTerm(formatPercent, new[] { operand, second, third });
+			}
+            ret.terms = termArray;
+			return ret;
+		}
+		#endregion
+
+		public bool IsConst => (strs.Length == 1);
+
+		public IOperandTerm GetIOperandTerm()
+		{
+			if((strs.Length == 2) && (strs[0].Length == 0) && (strs[1].Length == 0))
+				return terms[0];
+			return null;
+		}
+
+		public void Restructure(ExpressionMediator exm, bool tryTranslate=false)
+		{
+			if (strs.Length == 1)
+				return;
+			bool canRestructure = false;
+			for (int i = 0; i < terms.Length; i++)
+			{
+				terms[i] = terms[i].Restructure(exm);
+				if (terms[i] is SingleTerm)
+				{
+					canRestructure = true;
+				}
+			}
+			if (!canRestructure)
+				return;
+			List<string> strList = new List<string>();
+			List<IOperandTerm> termList = new List<IOperandTerm>();
+			strList.AddRange(strs);
+			termList.AddRange(terms);
+			for (int i = 0; i < termList.Count; i++)
+			{
+				if (termList[i] is SingleTerm)
+				{
+					string str = termList[i].GetStrValue(exm, tryTranslate);
+					strList[i] = strList[i] + str + strList[i + 1];
+					termList.RemoveAt(i);
+					strList.RemoveAt(i + 1);
+					i--;
+				}
+			}
+			strs = new string[strList.Count];
+			terms = new IOperandTerm[termList.Count];
+			strList.CopyTo(strs);
+			termList.CopyTo(terms);
+		}
+
+		public string GetString(ExpressionMediator exm, bool tryTranslate = false)
+		{
+			if (strs.Length == 1)
+				return strs[0];
+			StringBuilder builder = new StringBuilder(100);
+			for (int i = 0; i < strs.Length - 1; i++)
+			{
+                builder.Append(strs[i]);
+                //builder.Append(Translation.translate(terms[i].GetStrValue(exm)));
+                //If the tryTranslate is true we'll try to translate it
+                //HERE
+                builder.Append(terms[i].GetStrValue(exm, tryTranslate));
+            }
+			builder.Append(strs[strs.Length - 1]);
+            return builder.ToString();
+		}
+
+		#region FormattedStringMethod 書式付文字列の内部
+		private abstract class FormattedStringMethod : FunctionMethod
+		{
+			public FormattedStringMethod()
+			{
+				CanRestructure = true;
+				ReturnType = typeof(string);
+				argumentTypeArray = null;
+			}
+			public override string CheckArgumentType(string name, IOperandTerm[] arguments) { throw new ExeEE("型チェックは呼び出し元が行うこと"); }
+			public override Int64 GetIntValue(ExpressionMediator exm, IOperandTerm[] arguments) { throw new ExeEE("戻り値の型が違う"); }
+			public override SingleTerm GetReturnValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate) { return new SingleTerm(GetStrValue(exm, arguments, tryTranslate)); }
+		}
+
+		private sealed class FormatCurlyBrace : FormattedStringMethod
+		{
+			public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+			{
+				int nbrPad = 0;
+				string ret = arguments[0].GetIntValue(exm).ToString();
+				if (arguments[1] == null)
+					return ret;
+				//Bartoum: Engine bug fix, a negative value will make PadRight && PadLeft left.
+				nbrPad = (int)arguments[1].GetIntValue(exm);
+				if(nbrPad < 0)
+					nbrPad = 0;
+				if (arguments[2] != null)					
+					ret = ret.PadRight(nbrPad, ' ');//LEFT
+				else
+					ret = ret.PadLeft(nbrPad, ' ');//RIGHT
+
+				return ret;
+			}
+		}
+
+		private sealed class FormatPercent : FormattedStringMethod
+		{
+			public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+			{
+
+				if (arguments[1] != null)
+					tryTranslate = true;
+
+                //Changes by Bartoum
+                string ret = arguments[0].GetStrValue(exm, tryTranslate);
+				string original = ret;
+                //We try to translate the entire string. If the name of a csv variable was put alone in a variable like ARGS this will work.
+                //At this point we can't know where the name came from so we need to use ALL.
+                if(exm.Process.getCurrentLine != null && exm.Process.getCurrentLine.ToString().Contains("RETURNF"))
+                    tryTranslate = false;
+
+                if (tryTranslate){
+					ret = Translation.translate(ret, "ALL", tryTranslate);
+					//If it didn't work we strip everything after a number and all those characters -  [ ] 【 】and ( if ) is not present.
+					if(original == ret){
+						ret = Translation.translateALL(ret, "ALL");	
+					}
+				}
+				if (arguments[1] == null)
+					return ret;
+				int totalLength = (int)arguments[1].GetIntValue(exm);
+				int currentLength = LangManager.GetStrlenLang(ret);
+				totalLength -= currentLength - ret.Length;//全角文字の数だけマイナス。タブ文字?ゼロ幅文字?知るか!
+				if (totalLength < ret.Length)
+					return ret;//PadLeftは0未満を送ると例外を投げる
+				if (arguments[2] != null)
+					ret = ret.PadRight(totalLength, ' ');//LEFT
+				else
+					ret = ret.PadLeft(totalLength, ' ');//RIGHT
+				return ret;
+			}
+		}
+
+		private sealed class FormatYenAt : FormattedStringMethod
+		{//Operator のTernaryIntStrStrとやってることは同じ
+			public override string GetStrValue(ExpressionMediator exm, IOperandTerm[] arguments, bool tryTranslate = false)
+			{
+				return (arguments[0].GetIntValue(exm) != 0) ? arguments[1].GetStrValue(exm) : arguments[2].GetStrValue(exm);
+			}
+		}
+
+		#endregion
+	}
+}

+ 769 - 0
NTERA/Game/GameData/Variable/CharacterData.cs

@@ -0,0 +1,769 @@
+using System;
+using System.Collections.Generic;
+using MinorShift.Emuera.GameProc;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameData.Variable
+{
+
+	internal sealed class CharacterData : IDisposable
+	{
+		readonly Int64[] dataInteger;
+		readonly string[] dataString;
+		readonly Int64[][] dataIntegerArray;
+		readonly string[][] dataStringArray;
+		readonly Int64[][,] dataIntegerArray2D;
+		readonly string[][,] dataStringArray2D;
+		public Int64[] DataInteger => dataInteger;
+		public string[] DataString => dataString;
+		public Int64[][] DataIntegerArray => dataIntegerArray;
+		public string[][] DataStringArray => dataStringArray;
+		public Int64[][,] DataIntegerArray2D => dataIntegerArray2D;
+		public string[][,] DataStringArray2D => dataStringArray2D;
+
+		public List<object> UserDefCVarDataList { get; set; }
+
+		public CharacterData(ConstantData constant, VariableData varData)
+		{
+			dataInteger = new Int64[(int)VariableCode.__COUNT_CHARACTER_INTEGER__];
+			dataString = new string[(int)VariableCode.__COUNT_CHARACTER_STRING__];
+			dataIntegerArray = new Int64[(int)VariableCode.__COUNT_CHARACTER_INTEGER_ARRAY__][];
+			dataStringArray = new string[(int)VariableCode.__COUNT_CHARACTER_STRING_ARRAY__][];
+			dataIntegerArray2D = new Int64[(int)VariableCode.__COUNT_CHARACTER_INTEGER_ARRAY_2D__][,];
+			dataStringArray2D = new string[(int)VariableCode.__COUNT_CHARACTER_STRING_ARRAY_2D__][,];
+			for (int i = 0; i < dataIntegerArray.Length; i++)
+				dataIntegerArray[i] = new Int64[constant.CharacterIntArrayLength[i]];
+			for (int i = 0; i < dataStringArray.Length; i++)
+				dataStringArray[i] = new string[constant.CharacterStrArrayLength[i]];
+			for (int i = 0; i < dataIntegerArray2D.Length; i++)
+			{
+				Int64 length64 = constant.CharacterIntArray2DLength[i];
+				int length = (int)(length64 >> 32);
+				int length2 = (int)(length64 & 0x7FFFFFFF);
+				dataIntegerArray2D[i] = new Int64[length, length2];
+			}
+			for (int i = 0; i < dataStringArray2D.Length; i++)
+			{
+				Int64 length64 = constant.CharacterStrArray2DLength[i];
+				int length = (int)(length64 >> 32);
+				int length2 = (int)(length64 & 0x7FFFFFFF);
+				dataStringArray2D[i] = new string[length, length2];
+			}
+			UserDefCVarDataList = new List<object>();
+			for (int i = 0; i < varData.UserDefinedCharaVarList.Count; i++)
+			{
+				UserDefinedVariableData d = varData.UserDefinedCharaVarList[i].DimData;
+				object array = null;
+				if (d.TypeIsStr)
+				{
+					switch (d.Dimension)
+					{
+						case 1:
+							array = new string[d.Lengths[0]];
+							break;
+						case 2:
+							array = new string[d.Lengths[0], d.Lengths[1]];
+							break;
+						case 3:
+							array = new string[d.Lengths[0], d.Lengths[1], d.Lengths[2]];
+							break;
+					}
+				}
+				else
+				{
+					switch (d.Dimension)
+					{
+						case 1:
+							array = new Int64[d.Lengths[0]];
+							break;
+						case 2:
+							array = new Int64[d.Lengths[0], d.Lengths[1]];
+							break;
+						case 3:
+							array = new Int64[d.Lengths[0], d.Lengths[1], d.Lengths[2]];
+							break;
+					}
+				}
+				if (array == null)
+					throw new ExeEE("");
+				UserDefCVarDataList.Add(array);
+			}
+		}
+
+
+		public CharacterData(ConstantData constant, CharacterTemplate tmpl, VariableData varData)
+			: this(constant, varData)
+		{
+
+			dataInteger[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.NO] = tmpl.No;
+			dataString[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.NAME] = tmpl.Name;
+			dataString[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.CALLNAME] = tmpl.Callname;
+			dataString[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.NICKNAME] = tmpl.Nickname;
+			dataString[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.MASTERNAME] = tmpl.Mastername;
+			Int64[] array, array2;
+			array = dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.MAXBASE];
+			array2 = dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.BASE];
+			foreach (KeyValuePair<int, Int64> pair in tmpl.Maxbase)
+			{
+				array[pair.Key] = pair.Value;
+				array2[pair.Key] = pair.Value;
+			}
+			array = dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.MARK];
+			foreach (KeyValuePair<int, Int64> pair in tmpl.Mark)
+				array[pair.Key] = pair.Value;
+			array = dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.EXP];
+			foreach (KeyValuePair<int, Int64> pair in tmpl.Exp)
+				array[pair.Key] = pair.Value;
+			array = dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.ABL];
+			foreach (KeyValuePair<int, Int64> pair in tmpl.Abl)
+				array[pair.Key] = pair.Value;
+			array = dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.TALENT];
+			foreach (KeyValuePair<int, Int64> pair in tmpl.Talent)
+				array[pair.Key] = pair.Value;
+			array = dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.RELATION];
+			for (int i = 0; i < array.Length; i++)
+				array[i] = Config.RelationDef;
+			foreach (KeyValuePair<int, Int64> pair in tmpl.Relation)
+				array[pair.Key] = pair.Value;
+			array = dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.CFLAG];
+			foreach (KeyValuePair<int, Int64> pair in tmpl.CFlag)
+				array[pair.Key] = pair.Value;
+			array = dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.EQUIP];
+			foreach (KeyValuePair<int, Int64> pair in tmpl.Equip)
+				array[pair.Key] = pair.Value;
+			array = dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.JUEL];
+			foreach (KeyValuePair<int, Int64> pair in tmpl.Juel)
+				array[pair.Key] = pair.Value;
+			string[] arrays = dataStringArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.CSTR];
+			foreach (KeyValuePair<int, string> pair in tmpl.CStr)
+				arrays[pair.Key] = pair.Value;
+			/*
+			//tmpl.Maxbase.CopyTo(dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.MAXBASE], 0);
+            Buffer.BlockCopy(tmpl.Maxbase, 0, dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.MAXBASE], 0, 8 * constant.CharacterIntArrayLength[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.MAXBASE]);
+            //tmpl.Maxbase.CopyTo(dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.BASE], 0);
+            Buffer.BlockCopy(tmpl.Maxbase, 0, dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.BASE], 0, 8 * constant.CharacterIntArrayLength[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.BASE]);
+
+			//tmpl.Mark.CopyTo(dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.MARK], 0);
+            Buffer.BlockCopy(tmpl.Mark, 0, dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.MARK], 0, 8 * constant.CharacterIntArrayLength[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.MARK]);
+			//tmpl.Exp.CopyTo(dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.EXP], 0);
+            Buffer.BlockCopy(tmpl.Exp, 0, dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.EXP], 0, 8 * constant.CharacterIntArrayLength[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.EXP]);
+            //tmpl.Abl.CopyTo(dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.ABL], 0);
+            Buffer.BlockCopy(tmpl.Abl, 0, dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.ABL], 0, 8 * constant.CharacterIntArrayLength[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.ABL]);
+            //tmpl.Talent.CopyTo(dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.TALENT], 0);
+            Buffer.BlockCopy(tmpl.Talent, 0, dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.TALENT], 0, 8 * constant.CharacterIntArrayLength[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.TALENT]);
+            //tmpl.Relation.CopyTo(dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.RELATION], 0);
+            Buffer.BlockCopy(tmpl.Relation, 0, dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.RELATION], 0, 8 * constant.CharacterIntArrayLength[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.RELATION]);
+            //tmpl.CFlag.CopyTo(dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.CFLAG], 0);
+            Buffer.BlockCopy(tmpl.CFlag, 0, dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.CFLAG], 0, 8 * constant.CharacterIntArrayLength[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.CFLAG]);
+            //tmpl.Equip.CopyTo(dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.EQUIP], 0);
+            Buffer.BlockCopy(tmpl.Equip, 0, dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.EQUIP], 0, 8 * constant.CharacterIntArrayLength[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.EQUIP]);
+            //tmpl.Juel.CopyTo(dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.JUEL], 0);
+            Buffer.BlockCopy(tmpl.Juel, 0, dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.JUEL], 0, 8 * constant.CharacterIntArrayLength[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.JUEL]);
+
+			tmpl.CStr.CopyTo(dataStringArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.CSTR], 0);
+			*/
+		}
+
+		public static int[] CharacterVarLength(VariableCode code, ConstantData constant)
+		{
+			int[] ret = null;
+			VariableCode type = code & (VariableCode.__ARRAY_1D__ | VariableCode.__ARRAY_2D__ |
+				VariableCode.__ARRAY_3D__ | VariableCode.__INTEGER__ | VariableCode.__STRING__);
+			int i = (int)(code & VariableCode.__LOWERCASE__);
+			if (i >= 0xF0)
+				return null;
+			Int64 length64 = 0;
+			switch (type)
+			{
+				case VariableCode.__STRING__:
+				case VariableCode.__INTEGER__:
+					ret = new int[0];
+					break;
+				case VariableCode.__INTEGER__ | VariableCode.__ARRAY_1D__:
+					ret = new int[1];
+					ret[0] = constant.CharacterIntArrayLength[i];
+					break;
+				case VariableCode.__STRING__ | VariableCode.__ARRAY_1D__:
+					ret = new int[1];
+					ret[0] = constant.CharacterStrArrayLength[i];
+					break;
+				case VariableCode.__INTEGER__ | VariableCode.__ARRAY_2D__:
+					ret = new int[2];
+					length64 = constant.CharacterIntArray2DLength[i];
+					ret[0] = (int)(length64 >> 32);
+					ret[1] = (int)(length64 & 0x7FFFFFFF);
+					break;
+				case VariableCode.__STRING__ | VariableCode.__ARRAY_2D__:
+					ret = new int[2];
+					length64 = constant.CharacterStrArray2DLength[i];
+					ret[0] = (int)(length64 >> 32);
+					ret[1] = (int)(length64 & 0x7FFFFFFF);
+					break;
+				case VariableCode.__INTEGER__ | VariableCode.__ARRAY_3D__:
+					throw new NotImplCodeEE();
+				case VariableCode.__STRING__ | VariableCode.__ARRAY_3D__:
+					throw new NotImplCodeEE();
+			}
+			return ret;
+		}
+		public void CopyTo(CharacterData other, VariableData varData)
+		{
+			for (int i = 0; i < dataInteger.Length; i++)
+				other.dataInteger[i] = dataInteger[i];
+			for (int i = 0; i < dataString.Length; i++)
+				other.dataString[i] = dataString[i];
+
+			for (int i = 0; i < dataIntegerArray.Length; i++)
+				for (int j = 0; j < dataIntegerArray[i].Length; j++)
+					other.dataIntegerArray[i][j] = dataIntegerArray[i][j];
+			for (int i = 0; i < dataStringArray.Length; i++)
+				for (int j = 0; j < dataStringArray[i].Length; j++)
+					other.dataStringArray[i][j] = dataStringArray[i][j];
+
+			for (int i = 0; i < dataIntegerArray2D.Length; i++)
+			{
+				int length1 = dataIntegerArray2D[i].GetLength(0);
+				int length2 = dataIntegerArray2D[i].GetLength(1);
+				for (int j = 0; j < length1; j++)
+					for (int k = 0; k < length2; k++)
+						other.dataIntegerArray2D[i][j, k] = dataIntegerArray2D[i][j, k];
+			}
+			for (int i = 0; i < dataStringArray2D.Length; i++)
+			{
+				int length1 = dataStringArray2D[i].GetLength(0);
+				int length2 = dataStringArray2D[i].GetLength(1);
+				for (int j = 0; j < length1; j++)
+					for (int k = 0; k < length2; k++)
+						other.dataStringArray2D[i][j, k] = dataStringArray2D[i][j, k];
+			}
+            if (UserDefCVarDataList.Count > 0)
+            {
+                foreach (UserDefinedCharaVariableToken var in varData.UserDefinedCharaVarList)
+                {
+                    if (!var.IsCharacterData)
+                        continue;
+                    if (var.IsString)
+                    {
+                        if (var.IsArray1D)
+                        {
+                            int length = ((string[])(UserDefCVarDataList[var.ArrayIndex])).GetLength(0);
+                            for (int i = 0; i < length; i++)
+                                ((string[])(other.UserDefCVarDataList[var.ArrayIndex]))[i] = ((string[])(UserDefCVarDataList[var.ArrayIndex]))[i];
+                        }
+                        else if (var.IsArray2D)
+                        {
+                            int length1 = ((string[,])UserDefCVarDataList[var.ArrayIndex]).GetLength(0);
+                            int length2 = ((string[,])UserDefCVarDataList[var.ArrayIndex]).GetLength(1);
+                            for (int i = 0; i < length1; i++)
+                                for (int j = 0; j < length2; j++)
+                                    ((string[,])(other.UserDefCVarDataList[var.ArrayIndex]))[i, j] = ((string[,])(UserDefCVarDataList[var.ArrayIndex]))[i, j];
+                        }
+                    }
+                    else
+                    {
+                        if (var.IsArray1D)
+                        {
+                            int length = ((Int64[])(UserDefCVarDataList[var.ArrayIndex])).GetLength(0);
+                            for (int i = 0; i < length; i++)
+                                ((Int64[])(other.UserDefCVarDataList[var.ArrayIndex]))[i] = ((Int64[])(UserDefCVarDataList[var.ArrayIndex]))[i];
+                        }
+                        else if (var.IsArray2D)
+                        {
+                            int length1 = ((Int64[,])(UserDefCVarDataList[var.ArrayIndex])).GetLength(0);
+                            int length2 = ((Int64[,])(UserDefCVarDataList[var.ArrayIndex])).GetLength(1);
+                            for (int i = 0; i < length1; i++)
+                                for (int j = 0; j < length2; j++)
+                                    ((Int64[,])(other.UserDefCVarDataList[var.ArrayIndex]))[i, j] = ((Int64[,])(UserDefCVarDataList[var.ArrayIndex]))[i, j];
+                        }
+                    }
+                }
+            }
+		}
+
+		const int strCount = (int)VariableCode.__COUNT_SAVE_CHARACTER_STRING__;
+		const int intCount = (int)VariableCode.__COUNT_SAVE_CHARACTER_INTEGER__;
+		const int intArrayCount = (int)VariableCode.__COUNT_SAVE_CHARACTER_INTEGER_ARRAY__;
+		const int strArrayCount = (int)VariableCode.__COUNT_SAVE_CHARACTER_STRING_ARRAY__;
+
+		public void SaveToStream(EraDataWriter writer)
+		{
+
+			for (int i = 0; i < strCount; i++)
+				writer.Write(dataString[i]);
+			for (int i = 0; i < intCount; i++)
+				writer.Write(dataInteger[i]);
+			for (int i = 0; i < intArrayCount; i++)
+				writer.Write(dataIntegerArray[i]);
+			for (int i = 0; i < strArrayCount; i++)
+				writer.Write(dataStringArray[i]);
+		}
+
+		public void LoadFromStream(EraDataReader reader)
+		{
+
+			for (int i = 0; i < strCount; i++)
+				dataString[i] = reader.ReadString();
+			for (int i = 0; i < intCount; i++)
+				dataInteger[i] = reader.ReadInt64();
+			for (int i = 0; i < intArrayCount; i++)
+				reader.ReadInt64Array(dataIntegerArray[i]);
+			for (int i = 0; i < strArrayCount; i++)
+				reader.ReadStringArray(dataStringArray[i]);
+		}
+		public void SaveToStreamExtended(EraDataWriter writer)
+		{
+			List<VariableCode> codeList = null;
+
+			//dataString
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__CHARACTER_DATA__ | VariableCode.__STRING__);
+			foreach (VariableCode code in codeList)
+				writer.WriteExtended(code.ToString(), dataString[(int)VariableCode.__LOWERCASE__ & (int)code]);
+			writer.EmuSeparete();
+
+			//datainteger
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__CHARACTER_DATA__ | VariableCode.__INTEGER__);
+			foreach (VariableCode code in codeList)
+				writer.WriteExtended(code.ToString(), dataInteger[(int)VariableCode.__LOWERCASE__ & (int)code]);
+			writer.EmuSeparete();
+
+			//dataStringArray
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__CHARACTER_DATA__ | VariableCode.__ARRAY_1D__ | VariableCode.__STRING__);
+			foreach (VariableCode code in codeList)
+				writer.WriteExtended(code.ToString(), dataStringArray[(int)VariableCode.__LOWERCASE__ & (int)code]);
+			writer.EmuSeparete();
+
+			//dataIntegerArray
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__CHARACTER_DATA__ | VariableCode.__ARRAY_1D__ | VariableCode.__INTEGER__);
+			foreach (VariableCode code in codeList)
+				writer.WriteExtended(code.ToString(), dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)code]);
+			writer.EmuSeparete();
+
+			//dataStringArray2D
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__CHARACTER_DATA__ | VariableCode.__ARRAY_2D__ | VariableCode.__STRING__);
+			foreach (VariableCode code in codeList)
+				writer.WriteExtended(code.ToString(), dataStringArray2D[(int)VariableCode.__LOWERCASE__ & (int)code]);
+			writer.EmuSeparete();
+
+			//dataIntegerArray2D
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__CHARACTER_DATA__ | VariableCode.__ARRAY_2D__ | VariableCode.__INTEGER__);
+			foreach (VariableCode code in codeList)
+				writer.WriteExtended(code.ToString(), dataIntegerArray2D[(int)VariableCode.__LOWERCASE__ & (int)code]);
+			writer.EmuSeparete();
+		}
+
+		public void LoadFromStreamExtended(EraDataReader reader)
+		{
+			Dictionary<string, string> strDic = reader.ReadStringExtended();
+			Dictionary<string, Int64> intDic = reader.ReadInt64Extended();
+			Dictionary<string, List<string>> strListDic = reader.ReadStringArrayExtended();
+			Dictionary<string, List<Int64>> intListDic = reader.ReadInt64ArrayExtended();
+			Dictionary<string, List<string[]>> str2DListDic = reader.ReadStringArray2DExtended();
+			Dictionary<string, List<Int64[]>> int2DListDic = reader.ReadInt64Array2DExtended();
+
+			List<VariableCode> codeList = null;
+
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__CHARACTER_DATA__ | VariableCode.__STRING__);
+			foreach (VariableCode code in codeList)
+				if (strDic.ContainsKey(code.ToString()))
+					dataString[(int)VariableCode.__LOWERCASE__ & (int)code] = strDic[code.ToString()];
+
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__CHARACTER_DATA__ | VariableCode.__INTEGER__);
+			foreach (VariableCode code in codeList)
+				if (intDic.ContainsKey(code.ToString()))
+					dataInteger[(int)VariableCode.__LOWERCASE__ & (int)code] = intDic[code.ToString()];
+
+
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__CHARACTER_DATA__ | VariableCode.__ARRAY_1D__ | VariableCode.__STRING__);
+			foreach (VariableCode code in codeList)
+				if (strListDic.ContainsKey(code.ToString()))
+					copyListToArray(strListDic[code.ToString()], dataStringArray[(int)VariableCode.__LOWERCASE__ & (int)code]);
+
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__CHARACTER_DATA__ | VariableCode.__ARRAY_1D__ | VariableCode.__INTEGER__);
+			foreach (VariableCode code in codeList)
+				if (intListDic.ContainsKey(code.ToString()))
+					copyListToArray(intListDic[code.ToString()], dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)code]);
+
+			//dataStringArray2D
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__CHARACTER_DATA__ | VariableCode.__ARRAY_2D__ | VariableCode.__STRING__);
+			foreach (VariableCode code in codeList)
+				if (int2DListDic.ContainsKey(code.ToString()))
+					copyListToArray2D(str2DListDic[code.ToString()], dataStringArray2D[(int)VariableCode.__LOWERCASE__ & (int)code]);
+
+			//dataIntegerArray2D
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__CHARACTER_DATA__ | VariableCode.__ARRAY_2D__ | VariableCode.__INTEGER__);
+			foreach (VariableCode code in codeList)
+				if (int2DListDic.ContainsKey(code.ToString()))
+					copyListToArray2D(int2DListDic[code.ToString()], dataIntegerArray2D[(int)VariableCode.__LOWERCASE__ & (int)code]);
+		}
+
+		public void LoadFromStreamExtended_Old1802(EraDataReader reader)
+		{
+			Dictionary<string, string> strDic = reader.ReadStringExtended();
+			Dictionary<string, Int64> intDic = reader.ReadInt64Extended();
+			Dictionary<string, List<string>> strListDic = reader.ReadStringArrayExtended();
+			Dictionary<string, List<Int64>> intListDic = reader.ReadInt64ArrayExtended();
+
+			List<VariableCode> codeList = null;
+
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__CHARACTER_DATA__ | VariableCode.__STRING__);
+			foreach (VariableCode code in codeList)
+				if (strDic.ContainsKey(code.ToString()))
+					dataString[(int)VariableCode.__LOWERCASE__ & (int)code] = strDic[code.ToString()];
+
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__CHARACTER_DATA__ | VariableCode.__INTEGER__);
+			foreach (VariableCode code in codeList)
+				if (intDic.ContainsKey(code.ToString()))
+					dataInteger[(int)VariableCode.__LOWERCASE__ & (int)code] = intDic[code.ToString()];
+
+
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__CHARACTER_DATA__ | VariableCode.__ARRAY_1D__ | VariableCode.__STRING__);
+			foreach (VariableCode code in codeList)
+				if (strListDic.ContainsKey(code.ToString()))
+					copyListToArray(strListDic[code.ToString()], dataStringArray[(int)VariableCode.__LOWERCASE__ & (int)code]);
+
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__CHARACTER_DATA__ | VariableCode.__ARRAY_1D__ | VariableCode.__INTEGER__);
+			foreach (VariableCode code in codeList)
+				if (intListDic.ContainsKey(code.ToString()))
+					copyListToArray(intListDic[code.ToString()], dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)code]);
+
+		}
+
+		public void SaveToStreamBinary(EraBinaryDataWriter writer, VariableData varData)
+		{
+			//eramaker変数の保存
+			foreach (KeyValuePair<string, VariableToken> pair in varData.GetVarTokenDic())
+			{
+				VariableToken var = pair.Value;
+				if (!var.IsSavedata || !var.IsCharacterData || var.IsGlobal)
+					continue;
+				VariableCode code = var.Code;
+				VariableCode flag = code & (VariableCode.__ARRAY_1D__ | VariableCode.__ARRAY_2D__ | VariableCode.__ARRAY_3D__ | VariableCode.__STRING__ | VariableCode.__INTEGER__);
+				int CodeInt = var.CodeInt;
+				switch (flag)
+				{
+					case VariableCode.__INTEGER__:
+						writer.WriteWithKey(code.ToString(), dataInteger[CodeInt]);
+						break;
+					case VariableCode.__STRING__:
+						writer.WriteWithKey(code.ToString(), dataString[CodeInt]);
+						break;
+					case VariableCode.__INTEGER__ | VariableCode.__ARRAY_1D__:
+						writer.WriteWithKey(code.ToString(), dataIntegerArray[CodeInt]);
+						break;
+					case VariableCode.__STRING__ | VariableCode.__ARRAY_1D__:
+						writer.WriteWithKey(code.ToString(), dataStringArray[CodeInt]);
+						break;
+					case VariableCode.__INTEGER__ | VariableCode.__ARRAY_2D__:
+						writer.WriteWithKey(code.ToString(), dataIntegerArray2D[CodeInt]);
+						break;
+					case VariableCode.__STRING__ | VariableCode.__ARRAY_2D__:
+						writer.WriteWithKey(code.ToString(), dataStringArray2D[CodeInt]);
+						break;
+					//case VariableCode.__INTEGER__ | VariableCode.__ARRAY_3D__:
+					//    writer.Write(code.ToString(), dataIntegerArray3D[CodeInt]);
+					//    break;
+					//case VariableCode.__STRING__ | VariableCode.__ARRAY_3D__:
+					//    writer.Write(code.ToString(), dataStringArray3D[CodeInt]);
+					//    break;
+				}
+			}
+
+			//1813追加
+			if (UserDefCVarDataList.Count != 0)
+			{
+				writer.WriteSeparator();
+				//#DIM宣言変数の保存
+				foreach (UserDefinedCharaVariableToken var in varData.UserDefinedCharaVarList)
+				{
+					if (!var.IsSavedata || !var.IsCharacterData || var.IsGlobal)
+						continue;
+					writer.WriteWithKey(var.Name, UserDefCVarDataList[var.ArrayIndex]);
+				}
+			}
+
+			writer.WriteEOC();
+		}
+
+		public void LoadFromStreamBinary(EraBinaryDataReader reader)
+		{
+			int codeInt = 0;
+			bool userDefineData = false;
+			while (true)
+			{
+				KeyValuePair<string, EraSaveDataType> nameAndType = reader.ReadVariableCode();
+				VariableToken vToken = null;
+				object array = null;
+				if (nameAndType.Key != null)
+				{
+                    if (!GlobalStatic.IdentifierDictionary.getVarTokenIsForbid(nameAndType.Key))
+                        vToken = GlobalStatic.IdentifierDictionary.GetVariableToken(nameAndType.Key, null, false);
+					if (userDefineData)
+					{
+						if (vToken == null || !vToken.IsSavedata || !vToken.IsCharacterData || !(vToken is UserDefinedCharaVariableToken))
+							array = null;
+						else
+							array = UserDefCVarDataList[((UserDefinedCharaVariableToken)vToken).ArrayIndex];
+						vToken = null;
+					}
+					else
+					{
+                        if (vToken != null)
+                            codeInt = (int)VariableCode.__LOWERCASE__ & (int)vToken.Code;
+						array = null;
+					}
+				}
+				switch (nameAndType.Value)
+				{
+					case EraSaveDataType.Separator:
+						userDefineData = true;
+						continue;
+					case EraSaveDataType.EOF:
+					case EraSaveDataType.EOC:
+						goto whilebreak;
+					case EraSaveDataType.Int:
+						if (vToken == null || !vToken.IsInteger || vToken.Dimension != 0)
+							reader.ReadInt();
+						else
+							dataInteger[codeInt] = reader.ReadInt();
+						break;
+					case EraSaveDataType.Str:
+						if (vToken == null || !vToken.IsString || vToken.Dimension != 0)
+							reader.ReadString();
+						else
+							dataString[codeInt] = reader.ReadString();
+						break;
+					case EraSaveDataType.IntArray:
+						if (userDefineData && array != null)
+							reader.ReadIntArray(array as Int64[], true);
+						else if (vToken == null || !vToken.IsInteger || vToken.Dimension != 1)
+							reader.ReadIntArray(null, true);
+						else
+							reader.ReadIntArray(dataIntegerArray[codeInt], true);
+						break;
+					case EraSaveDataType.StrArray:
+						if (userDefineData && array != null)
+							reader.ReadStrArray(array as string[], true);
+						else if (vToken == null || !vToken.IsString || vToken.Dimension != 1)
+							reader.ReadStrArray(null, true);
+						else
+							reader.ReadStrArray(dataStringArray[codeInt], true);
+						break;
+					case EraSaveDataType.IntArray2D:
+						if (userDefineData && array != null)
+							reader.ReadIntArray2D(array as Int64[,], true);
+						else if (vToken == null || !vToken.IsInteger || vToken.Dimension != 2)
+							reader.ReadIntArray2D(null, true);
+						else
+							reader.ReadIntArray2D(dataIntegerArray2D[codeInt], true);
+						break;
+					case EraSaveDataType.StrArray2D:
+						if (userDefineData && array != null)
+							reader.ReadStrArray2D(array as string[,], true);
+						else if (vToken == null || !vToken.IsString || vToken.Dimension != 2)
+							reader.ReadStrArray2D(null, true);
+						else
+							reader.ReadStrArray2D(dataStringArray2D[codeInt], true);
+						break;
+					//case EraSaveDataType.IntArray3D:
+					//    if (vToken == null || !vToken.IsInteger || vToken.Dimension != 3)
+					//        reader.ReadIntArray3D(null, true);
+					//    else
+					//        reader.ReadIntArray3D(dataIntegerArray3D[codeInt], true);
+					//    break;
+					//case EraSaveDataType.StrArray3D:
+					//    if (vToken == null || !vToken.IsString || vToken.Dimension != 3)
+					//        reader.ReadStrArray3D(null, true);
+					//    else
+					//        reader.ReadStrArray3D(dataStringArray3D[codeInt], true);
+					//    break;
+					default:
+						throw new FileEE("データ異常");
+				}
+			}
+		whilebreak:
+			;
+		}
+
+
+		private void copyListToArray<T>(List<T> srcList, T[] destArray)
+		{
+			int count = Math.Min(srcList.Count, destArray.Length);
+			srcList.CopyTo(0, destArray, 0, count);
+			//for (int i = 0; i < count; i++)
+			//{
+			//    destArray[i] = srcList[i];
+			//}
+		}
+		private void copyListToArray2D<T>(List<T[]> srcList, T[,] destArray)
+		{
+			int countX = Math.Min(srcList.Count, destArray.GetLength(0));
+			int dLength = destArray.GetLength(1);
+			for (int x = 0; x < countX; x++)
+			{
+				T[] srcArray = srcList[x];
+				int countY = Math.Min(srcArray.Length, dLength);
+				for (int y = 0; y < countY; y++)
+				{
+					destArray[x, y] = srcArray[y];
+				}
+			}
+		}
+
+		public void setValueAll(int varInt, Int64 value)
+		{
+			dataInteger[varInt] = value;
+		}
+
+		public void setValueAll(int varInt, string value)
+		{
+			dataString[varInt] = value;
+		}
+
+		public void setValueAll1D(int varInt, Int64 value, int start, int end)
+		{
+			Int64[] array = dataIntegerArray[varInt];
+			for (int i = start; i < end; i++)
+				array[i] = value;
+		}
+
+		public void setValueAll1D(int varInt, string value, int start, int end)
+		{
+			string[] array = dataStringArray[varInt];
+			for (int i = start; i < end; i++)
+				array[i] = value;
+		}
+
+		public void setValueAll2D(int varInt, Int64 value)
+		{
+			Int64[,] array = dataIntegerArray2D[varInt];
+			int a1 = array.GetLength(0);
+			int a2 = array.GetLength(1);
+			for (int i = 0; i < a1; i++)
+				for (int j = 0; j < a2; j++)
+					array[i, j] = value;
+		}
+
+		public void setValueAll2D(int varInt, string value)
+		{
+			string[,] array = dataStringArray2D[varInt];
+			int a1 = array.GetLength(0);
+			int a2 = array.GetLength(1);
+			for (int i = 0; i < a1; i++)
+				for (int j = 0; j < a2; j++)
+					array[i, j] = value;
+		}
+
+		#region IDisposable メンバ
+
+		public void Dispose()
+		{
+			for (int i = 0; i < dataIntegerArray.Length; i++)
+				dataIntegerArray[i] = null;
+			for (int i = 0; i < dataStringArray.Length; i++)
+				dataStringArray[i] = null;
+			for (int i = 0; i < dataIntegerArray2D.Length; i++)
+				dataIntegerArray2D[i] = null;
+		}
+
+		#endregion
+		public Int64[] CFlag => dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.CFLAG];
+
+		public Int64 NO => dataInteger[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.NO];
+
+		#region sort
+		public IComparable temp_SortKey;
+		public int temp_CurrentOrder;
+		//Comparison<CharacterData>
+		public static int AscCharacterComparison(CharacterData x, CharacterData y)
+		{
+			int ret = x.temp_SortKey.CompareTo(y.temp_SortKey);
+			if (ret != 0)
+				return ret;
+			return x.temp_CurrentOrder.CompareTo(y.temp_CurrentOrder);
+		}
+		public static int DescCharacterComparison(CharacterData x, CharacterData y)
+		{
+			int ret = x.temp_SortKey.CompareTo(y.temp_SortKey);
+			if (ret != 0)
+				return -ret;
+			return x.temp_CurrentOrder.CompareTo(y.temp_CurrentOrder);
+		}
+
+		public void SetSortKey(VariableToken sortkey, Int64 elem64)
+		{
+			//チェック済み
+			//if (!sortkey.IsCharacterData)
+			//    throw new ExeEE("キャラクタ変数でない");
+			if (sortkey.IsString)
+			{
+                if (sortkey.IsArray2D)
+                {
+                    string[,] array;
+                    if (sortkey is UserDefinedCharaVariableToken)
+                        array = (string[,])UserDefCVarDataList[((UserDefinedCharaVariableToken)sortkey).ArrayIndex];
+                    else
+                        array = dataStringArray2D[sortkey.CodeInt];
+                    int elem1 = (int)(elem64 >> 32);
+                    int elem2 = (int)(elem64 & 0x7FFFFFFF);
+                    if (elem1 < 0 || elem1 >= array.GetLength(0) || elem2 < 0 || elem2 >= array.GetLength(1))
+                        throw new CodeEE("ソートキーが配列外を参照しています");
+                    temp_SortKey = array[elem1, elem2];
+                }
+                else if (sortkey.IsArray1D)
+                {
+                    string[] array;
+                    if (sortkey is UserDefinedCharaVariableToken)
+                        array = (string[])UserDefCVarDataList[((UserDefinedCharaVariableToken)sortkey).ArrayIndex];
+                    else
+                        array = dataStringArray[sortkey.CodeInt];
+                    if (elem64 < 0 || elem64 >= array.Length)
+                        throw new CodeEE("ソートキーが配列外を参照しています");
+                    if (array[(int)elem64] != null)
+                        temp_SortKey = array[(int)elem64];
+                    else
+                        temp_SortKey = "";
+                }
+                else
+                {
+                    //ユーザー定義キャラ変数は非配列がない
+                    if (dataString[sortkey.CodeInt] != null)
+                        temp_SortKey = dataString[sortkey.CodeInt];
+                    else
+                        temp_SortKey = "";
+                }
+			}
+			else
+			{
+				if (sortkey.IsArray2D)
+				{
+                    Int64[,] array;
+                    if (sortkey is UserDefinedCharaVariableToken)
+                        array = (Int64[,])UserDefCVarDataList[((UserDefinedCharaVariableToken)sortkey).ArrayIndex];
+                    else
+                        array = dataIntegerArray2D[sortkey.CodeInt];
+					int elem1 = (int)(elem64 >> 32);
+					int elem2 = (int)(elem64 & 0x7FFFFFFF);
+					if (elem1 < 0 || elem1 >= array.GetLength(0) || elem2 < 0 || elem2 >= array.GetLength(1))
+						throw new CodeEE("ソートキーが配列外を参照しています");
+					temp_SortKey = array[elem1, elem2];
+				}
+				else if (sortkey.IsArray1D)
+				{
+                    Int64[] array;
+                    if (sortkey is UserDefinedCharaVariableToken)
+                        array = (Int64[])UserDefCVarDataList[((UserDefinedCharaVariableToken)sortkey).ArrayIndex];
+                    else
+                        array = dataIntegerArray[sortkey.CodeInt];
+					if (elem64 < 0 || elem64 >= array.Length)
+						throw new CodeEE("ソートキーが配列外を参照しています");
+					temp_SortKey = array[(int)elem64];
+				}
+				else
+				{
+					temp_SortKey = dataInteger[sortkey.CodeInt];
+				}
+			}
+		}
+		#endregion
+	}
+}

+ 532 - 0
NTERA/Game/GameData/Variable/Translation.cs

@@ -0,0 +1,532 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Media;
+using System.Text.RegularExpressions;
+using MinorShift.Emuera.Sub;
+using NTERA.Interop;
+
+// Created by Bartoum.
+// Class that is initialized one time in Constant data.
+// Create a dictionary of dictionary for each *_TR.csv that is there
+namespace MinorShift.Emuera.GameData.Variable
+{
+    internal class Translation // JVN: making it internal allows to pass the Emueraconsole by reference here
+    {
+
+        public static Dictionary<string, Dictionary<string, string>> nameTlDictionnary;
+        public static string[] fileArray;
+		private static ArrayList memoryArray;
+		private static string lastRet;
+        private static int nbrMemory = 20;
+        private static bool canLoadParam;
+        private static Dictionary<Int64, TRCharaTemplate> TRCharaList; // JVN: A simple dictionary, only needs the character number as a key.
+        private static IConsole output; // JVN: Console access is a must, debug is life, debug is <3
+
+        public enum CharaData
+        { Name = 0, Callname, Nickname, Mastername, CSTR} // JVN: enums are noice.
+
+        // JVN: Templates are good too. Make it private too, because it's only used interally
+        private class TRCharaTemplate
+        {
+            public Int64 No;
+            public string Name;
+            public string Callname;
+            public string Nickname;
+            public string Mastername;
+            public Dictionary<Int32, string> CStr;
+
+            // JVN: Construct
+            public TRCharaTemplate(Int64 aNo = 0, string aName ="", string aCall ="", string aNick = "", string aMaster = "")
+            {
+                No = aNo;
+                Name = aName;
+                Callname = aCall;
+                Nickname = aNick;
+                Mastername = aMaster;
+                CStr = new Dictionary<Int32, string>();
+            }
+
+            // JVN: Cloning is important for what we need to do
+            public TRCharaTemplate Clone()
+            {
+                TRCharaTemplate tmp = new TRCharaTemplate(No, Name, Callname, Nickname, Mastername);
+                foreach (KeyValuePair<Int32, string> cloneData in CStr)
+                {
+                    tmp.CStr.Add(cloneData.Key, cloneData.Value);
+                }
+                return tmp;
+            }
+        }
+
+        //Constructor
+        public Translation(string csvDir, ref IConsole console, bool pcanLoadParam)
+		{
+            output = console; // JVN: Debugging is important, and the console allows for that
+			canLoadParam = pcanLoadParam;
+			loadTranslationData(csvDir);
+            loadCharacterTranslationData(csvDir);
+        }
+
+        //JVN: I just wants it
+        public static bool isCanLoadParam() { return canLoadParam; }
+
+        private const bool translateCSVAnyways = false; // TODO: make this configurable, somehow, probably via CSV setting?
+
+		//Normal way to translate original is the string of the variable we are working with and name is the file where it lives ex: Talent or Source. It can also be ALL.
+		public static string translate(string original, string name, bool tryTranslate){
+			string ret;
+            ret = original;
+            if (name == "Palam" && canLoadParam)
+                name = "Param";
+
+			
+			
+            //Change the original term to the translated one;
+			if (original != null){		
+				if(nameTlDictionnary.ContainsKey(name) && nameTlDictionnary[name].ContainsKey(original)){
+					if(tryTranslate || translateCSVAnyways)
+                    {
+						ret = nameTlDictionnary[name][original];
+                        lastRet = ret;
+                    }
+					else{
+                        if (memoryArray.IndexOf(original + "," + name) == -1)
+                            memoryArray.Add(original + "," + name);
+
+                        if (memoryArray.Count >= nbrMemory)
+                            memoryArray.RemoveAt(0);
+					}							
+				}
+			}	
+            return ret;
+		}
+
+        // JVN: Character string translation
+        public static string translateChara(Int64 character, CharaData varname, string oriString, Int32 index = 0) {
+            switch (varname)
+            {
+                case CharaData.Name:        // "NAME","名前"
+                    if (TRCharaList.ContainsKey(character)) return TRCharaList[character].Name;
+                    break;
+                case CharaData.Callname:    // "CALLNAME","呼び名"
+                    if (TRCharaList.ContainsKey(character)) return TRCharaList[character].Callname;
+                    break;
+                case CharaData.Nickname:    // "NICKNAME","あだ名"
+                    if (TRCharaList.ContainsKey(character)) return TRCharaList[character].Nickname;
+                    break;
+                case CharaData.Mastername:  // "MASTERNAME","主人の呼び方"
+                    if (TRCharaList.ContainsKey(character)) return TRCharaList[character].Mastername;
+                    break;
+                case CharaData.CSTR:        // "CSTR"
+                    if (TRCharaList.ContainsKey(character))
+                        if (TRCharaList[character].CStr.ContainsKey(index)) return TRCharaList[character].CStr[index];
+                    break;
+            }
+            return oriString;
+        }
+
+        //The last way to translate something.
+        public static string translateALL(string original, string pname ="ALL")
+        {
+            string ret = original;
+
+            if (!String.IsNullOrEmpty(original))
+            {
+                bool found = false;
+                string[] temp;
+
+                int i = memoryArray.Count - 1;
+                if (!String.IsNullOrEmpty(lastRet) && original.Contains(lastRet))
+                {
+                    //output.Print("Did it brah\n");
+                    found = true;
+                }
+
+                while (i >= 0 && !found)
+                {
+                    temp = memoryArray[i].ToString().Split(',');
+                   // output.Print("Checked: " + original + " against: " + temp[0] + " \\ ");
+                    if (original.Contains(temp[0]))
+                    {
+                        //output.Print("FOUND IT with:" +temp[1]+ " " + temp[0] + " \n");
+                        ret = original.Replace(temp[0], nameTlDictionnary[temp[1]][temp[0]]);
+                        found = true;
+                        //memoryArray.Remove(temp[0] + "," + temp[1]);         
+                    }
+                    i--;
+                }
+                //output.Print("\n");
+
+
+                if (!found)
+                {
+                    if (nameTlDictionnary.ContainsKey(pname))
+                    {
+                        //We try to strip all the stuff around the csv variable name
+                        //Remove all numbers, remove LV and all special characters bellow
+                        //Parantheses are only remove if only numbers where inside them because some variable name use them
+
+                        bool numPresent = true;
+
+
+                        //We remove all the numbers
+                        while (numPresent)
+                        {
+                            if (Regex.Match(original, @"\d+").Value != "")
+                            {
+                                original = original.Replace(Regex.Match(original, @"\d+").Value, "");
+                            }
+                            else
+                            {
+                                numPresent = false;
+                            }
+                        }
+                        //original = original.Replace("-", "");
+                        //original = original.Replace("()", "");
+                        original = original.Replace("【", "");
+                        original = original.Replace("】", "");
+                        original = original.Replace("[", "");
+                        original = original.Replace("]", "");
+                        original = original.Replace("LV", "");
+                        original = original.Replace("『", "");
+                        original = original.Replace("』", "");
+                        /*
+                        original = original.Replace("1Lv", "");
+                        original = original.Replace("2Lv", "");
+                        original = original.Replace("3Lv", "");
+                        original = original.Replace("4Lv", "");
+                        original = original.Replace("5Lv", "");		
+                        */
+                        //output.Print("Did it the old stupid way\n");
+                        if (nameTlDictionnary[pname].ContainsKey(original))
+                        {
+                            ret = ret.Replace(original, nameTlDictionnary[pname][original]);
+                            //output.Print("Found it the stupid way");
+                        }
+                    }
+                }
+            }
+            return ret;
+        }
+
+        private void loadTranslationData(string csvDir)
+		{
+			fileArray = new[] {"Abl", "Talent", "Exp", "Mark", "Palam", "Param", "Item","Train", "Base","Source", "Ex", "EQUIP", "TEQUIP", "Flag", "TFLAG", "Cflag", "Tcvar", "CSTR", "Stain","Cdflag1", "Cdflag2", "Str", "TSTR","SaveStr", "GLOBAL", "GLOBALS","ALL"};
+			nameTlDictionnary = new Dictionary<string, Dictionary<string, string> >();
+			memoryArray = new ArrayList();
+            string temp;
+
+            for (int i = 0; i < fileArray.Length;i++){
+				Dictionary<string,string> tempDictionnary = new Dictionary<string,string>();
+				
+				string csvPath = csvDir + fileArray[i] + "_TR.csv";
+				if (!File.Exists(csvPath))
+					continue;
+				
+				EraStreamReader eReader = new EraStreamReader(false);
+				
+				if (!eReader.Open(csvPath))
+					throw new Exception(eReader.Filename + " can't be opened");
+
+				ScriptPosition position = null;
+				try
+				{
+					StringStream st = null;
+					while ((st = eReader.ReadEnabledLine()) != null)
+					{
+
+						position = new ScriptPosition(eReader.Filename, eReader.LineNo, st.RowString);
+                        temp = st.Substring();
+                        if (temp[0] == ';')
+                            continue;
+						if (temp.Contains(";"))
+							temp = temp.Substring(0, temp.IndexOf(';'));
+
+						string[] tokens = temp.Split(',');
+
+                        //Make it crash with a good message if there's not a ","
+                        if(tokens.Length != 2)
+                            throw new Exception("A line must have one \",\" to separate the original from the new string. The line with the problem begins by : " + tokens[0]);
+
+                        //Make it crash with a good message if the same key is present two times
+                        if (tempDictionnary.ContainsKey(tokens[0]))
+							throw new Exception("You can only have one occurence of the same key. " + tokens[0] + " is already linked to : " + tempDictionnary[tokens[0]]);
+						
+						tempDictionnary.Add(tokens[0], tokens[1]);		
+					}
+					nameTlDictionnary.Add(fileArray[i], tempDictionnary);
+				}
+				catch(Exception e)
+				{
+                    throw new Exception(e.Message);
+				}
+				finally
+				{
+					eReader.Close();
+                }
+            }
+        }
+
+        //Receive the line that is being interpreted as a string.
+        //if there's a TALENTXXX  in this string it will return the XXX
+        //if not it will return ALL.
+        public static string searchParentFile(string name)
+        {
+            string ret = "ALL";
+            int i = 0;
+            bool found = false;
+
+            try
+            {
+				 if (name.Contains("NAME")){
+					 while (i < fileArray.Length - 1 && !found)
+					 {
+						 if (name.Contains(fileArray[i].ToUpper() + "NAME"))
+						 {
+							 ret = fileArray[i];
+							 found = true;
+							 }
+							 i++;
+					 }
+			}
+				
+
+
+            }
+            catch(Exception e)
+            {
+                throw new Exception(e.Message);
+            }
+
+            return ret;
+        }
+
+        // JVN: Loading fuctions for TRCHARA*.CSV
+        private void loadCharacterTranslationData(string csvDir, bool useCompatiName = false, bool disp = false)
+        {
+            if (!Directory.Exists(csvDir))
+                return;
+            TRCharaList = new Dictionary<long, TRCharaTemplate>();
+            // JVN: Search the CSV and subdirectories for TRCHARA files and send that to a function for futher loading
+                List<KeyValuePair<string, string>> csvPaths = Config.GetFiles(csvDir, "TRCHARA*.CSV");
+            for (int i = 0; i < csvPaths.Count; i++)
+                loadTRCharacterDataFile(csvPaths[i].Value, csvPaths[i].Key, disp);
+
+            if (useCompatiName) // check for the compatibility flag, just in case
+            {
+                foreach (KeyValuePair<Int64, TRCharaTemplate> tmpl in TRCharaList)
+                    if (string.IsNullOrEmpty(tmpl.Value.Callname))
+                        tmpl.Value.Callname = tmpl.Value.Name;
+            }
+        }
+
+        // JVN: Loads individual character files and data
+        private void loadTRCharacterDataFile(string csvPath, string csvName, bool disp)
+        {
+            bool NextCharacter = false;
+            EraStreamReader eReader = new EraStreamReader(false);
+            if (!eReader.Open(csvPath, csvName))
+            {
+                output.PrintError("File " + eReader.Filename + " has failed to open");
+                return;
+            }
+            ScriptPosition position = null;
+            if (disp)
+                output.PrintSystemLine(eReader.Filename + " is being read・・・");
+            try
+            {
+                TRCharaTemplate tmpl = null;
+                Int64 index = -1;
+                StringStream st = null;
+                bool Alive = true;
+                while (Alive || NextCharacter)
+                {
+                    Alive = (st = eReader.ReadEnabledLine()) != null;
+                    if (NextCharacter)
+                    {
+                        if (tmpl != null) { 
+                        TRCharaTemplate tmp = tmpl.Clone();
+                        TRCharaList.Add(index, tmp);
+                        tmpl = null;
+                        NextCharacter = false;
+                        }
+                        if (!Alive) break;
+                    }
+                    position = new ScriptPosition(eReader.Filename, eReader.LineNo, st.RowString);
+                    string[] tokens = st.Substring().Split(',');
+                    if (tokens.Length < 2)
+                    {
+                        ParserMediator.Warn("\",\" is needed", position, 1);
+                        continue;
+                    }
+                    if (tokens[0].Length == 0)
+                    {
+                        ParserMediator.Warn("Begins in \",\"", position, 1);
+                        continue;
+                    }
+                    if ((tokens[0].Equals("NO", Config.SCVariable)) || (tokens[0].Equals("番号", Config.SCVariable)))
+                    {
+                        if (tmpl != null)
+                        {
+                            ParserMediator.Warn("Character number has been defined twice", position, 1);
+                            continue;
+                        }
+                        if (!Int64.TryParse(tokens[1].TrimEnd(), out index))
+                        {
+                            ParserMediator.Warn(tokens[1] + " cannot be changed into an integer", position, 1);
+                            continue;
+                        }
+                        tmpl = new TRCharaTemplate(index);
+                        continue;
+                    }
+                    if (tmpl == null)
+                    {
+                        ParserMediator.Warn("Data started before the character number is defined", position, 1);
+                        continue;
+                    }
+                    NextCharacter = toTRCharaTemplate(position, tmpl, tokens);
+                }
+
+            }
+            catch (Exception e)
+            {
+                SystemSounds.Hand.Play();
+                if (position != null)
+                {
+                    output.PrintError(e.ToString());
+                    ParserMediator.Warn("An unexpected error has occurred", position, 3);
+                }
+                else
+                {
+                    output.PrintError("An unexpected error has occurred");
+                }
+                output.PrintError("");
+            }
+            finally
+            {
+                eReader.Dispose();
+            }
+        }
+
+        // JVN: Copy of the ConstantData's tryTo64
+        private bool tryToInt64(string str, out Int64 p)
+        {
+            p = -1;
+            if (string.IsNullOrEmpty(str))
+                return false;
+            StringStream st = new StringStream(str);
+            int sign = 1;
+            if (st.Current == '+')
+                st.ShiftNext();
+            else if (st.Current == '-')
+            {
+                sign = -1;
+                st.ShiftNext();
+            }
+            //1803beta005 char.IsDigitは全角数字とかまでひろってしまうので・・・
+            //if (!char.IsDigit(st.Current))
+            // return false;
+            switch (st.Current)
+            {
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                case '8':
+                case '9':
+                    break;
+                default:
+                    return false;
+            }
+            try
+            {
+                p = LexicalAnalyzer.ReadInt64(st, false);
+                p = p * sign;
+            }
+            catch
+            {
+                return false;
+            }
+            return true;
+        }
+
+
+        // JVN: Takes care of each line being read and sends result back. That works too. Returns false if 'ENDCHR' is found.
+        private bool toTRCharaTemplate(ScriptPosition position, TRCharaTemplate chara, string[] tokens)
+        {
+            if (chara == null)
+                return true;
+            int length = -1;
+            Int64 p1 = -1;
+            //Int64 p2 = -1;
+            //Dictionary<int, Int64> intArray = null;
+            Dictionary<int, string> strArray = null;
+            Dictionary<string, int> namearray = null;
+
+            string errPos = null;
+            string varname = tokens[0].ToUpper();
+            switch (varname)
+            {
+                case "NAME":
+                case "名前":
+                    chara.Name = tokens[1];
+                    return false;
+                case "CALLNAME":
+                case "呼び名":
+                    chara.Callname = tokens[1];
+                    return false;
+                case "NICKNAME":
+                case "あだ名":
+                    chara.Nickname = tokens[1];
+                    return false;
+                case "MASTERNAME":
+                case "主人の呼び方":
+                    chara.Mastername = tokens[1];
+                    return false;
+                case "CSTR":
+                    strArray = chara.CStr;
+                    errPos = "cstr.csv";
+                    break;
+                case "ENDCHR":
+                case "ENDCHAR":
+                    return true;
+                default:
+                    ParserMediator.Warn("\"" + tokens[0] + "\" cannot be interpreted", position, 1);
+                    return false;
+            }
+            bool p1isNumeric = tryToInt64(tokens[1].TrimEnd(), out p1);
+            int index = (int)p1;
+            if ((!p1isNumeric) && (namearray != null))
+            {
+	            if (!namearray.TryGetValue(tokens[1], out index))
+                {
+                    ParserMediator.Warn(errPos + ": \"" + tokens[1] + "\" is undefined", position, 1);
+                    return false;
+                }
+
+	            if (index >= length)
+	            {
+		            ParserMediator.Warn("\"" + tokens[1] + "\" is out of bounds of the array", position, 1);
+		            return false;
+	            }
+            }
+
+            if (strArray != null)
+            {
+                if (tokens.Length < 3)
+                    ParserMediator.Warn("There's no third identifier", position, 1);
+                if (strArray.ContainsKey(index))
+                    ParserMediator.Warn(varname + "'s #" + index + " element is already denied (Overwritting it)", position, 1);
+                strArray[index] = tokens[2];
+            }
+            return false;
+        }
+
+    }
+}

+ 284 - 0
NTERA/Game/GameData/Variable/VariableCode.cs

@@ -0,0 +1,284 @@
+namespace MinorShift.Emuera.GameData.Variable
+{
+	internal enum VariableCode
+	{
+		__NULL__ = 0x00000000,
+        __CAN_FORBID__ = 0x00010000,
+		__INTEGER__ = 0x00020000,
+		__STRING__ = 0x00040000,
+		__ARRAY_1D__ = 0x00080000,
+		__CHARACTER_DATA__ = 0x00100000,//第一引数を省略可能。TARGETで補う
+		__UNCHANGEABLE__ = 0x00400000,//変更不可属性
+		__CALC__ = 0x00800000,//計算値
+		__EXTENDED__ = 0x01000000,//Emueraで追加した変数
+		__LOCAL__ = 0x02000000,//ローカル変数。
+		__GLOBAL__ = 0x04000000,//グローバル変数。
+		__ARRAY_2D__ = 0x08000000,//二次元配列。キャラクタ変数フラグと排他
+		__SAVE_EXTENDED__ = 0x10000000,//拡張セーブ機能によってセーブするべき変数。
+							//このフラグを立てておけば勝手にセーブされる(はず)。名前を変えると正常にロードできなくなるので注意。
+        __ARRAY_3D__ = 0x20000000,//三次元配列
+        __CONSTANT__ = 0x40000000,//完全定数CSVから読み込まれる~NAME系がこれに該当
+
+		__UPPERCASE__ = 0x7FFF0000,
+		__LOWERCASE__ = 0x0000FFFF,
+
+		__COUNT_SAVE_INTEGER__ = 0x00,//実は全て配列
+		__COUNT_INTEGER__ = 0x00,
+		//PALAMLV, EXPLV, RESULT, COUNT, TARGET, SELECTCOMは禁止設定不可
+		DAY = 0x00 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//経過日数。
+		MONEY = 0x01 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//金
+		ITEM = 0x02 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//所持数
+		FLAG = 0x03 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//フラグ
+		TFLAG = 0x04 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//一時フラグ
+		UP = 0x05 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//調教中パラメータの上昇値。indexはPALAM.CSVのもの。
+		PALAMLV = 0x06 | __INTEGER__ | __ARRAY_1D__,//調教中パラメータのレベルわけの境界値。境界値を越えると珠の数が多くなる。
+		EXPLV = 0x07 | __INTEGER__ | __ARRAY_1D__,//経験のレベルわけの境界値。境界値を越えると調教の効果が上がる。
+		EJAC = 0x08 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//射精チェックのための一時変数。
+		DOWN = 0x09 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//調教中パラメータの減少値。indexはPALAM.CSVのもの
+		RESULT = 0x0A | __INTEGER__ | __ARRAY_1D__,//戻り値(数値)
+		COUNT = 0x0B | __INTEGER__ | __ARRAY_1D__,//繰り返しカウンター
+		TARGET = 0x0C | __INTEGER__ | __ARRAY_1D__,//調教中のキャラの"登録番号"
+		ASSI = 0x0D | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//助手のキャラの"登録番号"
+		MASTER = 0x0E | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//主人公のキャラの"登録番号"。通常0
+		NOITEM = 0x0F | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//アイテムが存在しないか?存在しない設定なら1.GAMEBASE.CSV
+		LOSEBASE = 0x10 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//基礎パラメータの減少値。通常はLOSEBASE:0が体力の消耗、LOSEBASE:1が気力の消耗。
+		SELECTCOM = 0x11 | __INTEGER__ | __ARRAY_1D__,//選択されたコマンド。TRAIN.CSVのものと同じ
+		ASSIPLAY = 0x12 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//助手現在調教しているか?1 = true, 0 = false
+		PREVCOM = 0x13 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//前回のコマンド。
+		NOTUSE_14 = 0x14 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//eramakerではRANDが格納されている領域。
+		NOTUSE_15 = 0x15 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//eramakerではCHARANUMが格納されている領域。
+		TIME = 0x16 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//時刻
+		ITEMSALES = 0x17 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//売っているか?
+		PLAYER = 0x18 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//調教している人間のキャラの登録番号。通常はMASTERかASSI
+		NEXTCOM = 0x19 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//調教している人間のキャラの登録番号。通常はMASTERかASSI
+		PBAND = 0x1A | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//ペニスバンドのアイテム番号
+		BOUGHT = 0x1B | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//直前に購入したアイテム番号
+		NOTUSE_1C = 0x1C | __INTEGER__ | __ARRAY_1D__,//未使用領域
+		NOTUSE_1D = 0x1D | __INTEGER__ | __ARRAY_1D__,//未使用領域
+		A = 0x1E | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,//汎用変数
+        B = 0x1F | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        C = 0x20 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        D = 0x21 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        E = 0x22 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        F = 0x23 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        G = 0x24 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        H = 0x25 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        I = 0x26 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        J = 0x27 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        K = 0x28 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        L = 0x29 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        M = 0x2A | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        N = 0x2B | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        O = 0x2C | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        P = 0x2D | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        Q = 0x2E | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        R = 0x2F | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        S = 0x30 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        T = 0x31 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        U = 0x32 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        V = 0x33 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        W = 0x34 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        X = 0x35 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        Y = 0x36 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+        Z = 0x37 | __INTEGER__ | __ARRAY_1D__ | __CAN_FORBID__,
+		NOTUSE_38 = 0x38 | __INTEGER__ | __ARRAY_1D__,//未使用領域
+		NOTUSE_39 = 0x39 | __INTEGER__ | __ARRAY_1D__,//未使用領域
+		NOTUSE_3A = 0x3A | __INTEGER__ | __ARRAY_1D__,//未使用領域
+		NOTUSE_3B = 0x3B | __INTEGER__ | __ARRAY_1D__,//未使用領域
+		__COUNT_SAVE_INTEGER_ARRAY__ = 0x3C,
+
+		ITEMPRICE = 0x3C | __INTEGER__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CAN_FORBID__,//アイテム価格
+		LOCAL = 0x3D | __INTEGER__ | __ARRAY_1D__ | __LOCAL__ | __EXTENDED__ | __CAN_FORBID__,//ローカル変数
+		ARG = 0x3E | __INTEGER__ | __ARRAY_1D__ | __LOCAL__ | __EXTENDED__ | __CAN_FORBID__,//関数の引数用
+		GLOBAL = 0x3F | __INTEGER__ | __ARRAY_1D__ | __GLOBAL__ | __EXTENDED__ | __CAN_FORBID__,//グローバル数値型変数
+		RANDDATA = 0x40 | __INTEGER__ | __ARRAY_1D__ | __SAVE_EXTENDED__ | __EXTENDED__,//グローバル数値型変数
+		__COUNT_INTEGER_ARRAY__ = 0x41,
+
+
+		SAVESTR = 0x00 | __STRING__ | __ARRAY_1D__ | __CAN_FORBID__,//文字列データ。保存される
+		__COUNT_SAVE_STRING_ARRAY__ = 0x01,
+
+
+		//RESULTSは禁止設定不可
+		STR = 0x01 | __STRING__ | __ARRAY_1D__ | __CAN_FORBID__,//文字列データ。STR.CSV。書き換え可能。
+		RESULTS = 0x02 | __STRING__ | __ARRAY_1D__,//実はこいつも配列
+		LOCALS = 0x03 | __STRING__ | __ARRAY_1D__ | __LOCAL__ | __EXTENDED__ | __CAN_FORBID__, //ローカル文字列変数
+		ARGS = 0x04 | __STRING__ | __ARRAY_1D__ | __LOCAL__ | __EXTENDED__ | __CAN_FORBID__,//関数の引数用
+		GLOBALS = 0x05 | __STRING__ | __ARRAY_1D__ | __GLOBAL__ | __EXTENDED__ | __CAN_FORBID__, //グローバル文字列変数
+		TSTR = 0x06 | __STRING__ | __ARRAY_1D__ | __SAVE_EXTENDED__ | __EXTENDED__ | __CAN_FORBID__,
+
+		__COUNT_STRING_ARRAY__ = 0x07,
+
+
+
+		SAVEDATA_TEXT = 0x00 | __STRING__ | __EXTENDED__, //セーブ時につかう文字列。PUTFORMで追加できるやつ
+		__COUNT_SAVE_STRING__ = 0x00,
+		__COUNT_STRING__ = 0x01,
+
+
+
+
+
+
+		ISASSI = 0x00 | __INTEGER__ | __CHARACTER_DATA__,//助手か?1 = ture, 0 = false
+		NO = 0x01 | __INTEGER__ | __CHARACTER_DATA__,//キャラ番号
+
+		__COUNT_SAVE_CHARACTER_INTEGER__ = 0x02,//こいつらは配列ではないらしい。
+		__COUNT_CHARACTER_INTEGER__ = 0x02,
+
+		BASE = 0x00 | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __CAN_FORBID__,//基礎パラメータ。
+		MAXBASE = 0x01 | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __CAN_FORBID__,//基礎パラメータの最大値。
+		ABL = 0x02 | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __CAN_FORBID__,//能力。ABL.CSV
+		TALENT = 0x03 | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __CAN_FORBID__,//素質。TALENT.CSV
+		EXP = 0x04 | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __CAN_FORBID__,//経験。EXP.CSV
+		MARK = 0x05 | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __CAN_FORBID__,//刻印。MARK.CSV
+		PALAM = 0x06 | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __CAN_FORBID__,//調教中パラメータ。PALAM.CSV
+		SOURCE = 0x07 | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __CAN_FORBID__,//調教中パラメータ。直前のコマンドで発生した調教ソース。
+		EX = 0x08 | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __CAN_FORBID__,//調教中パラメータ。この調教中、どこで何回絶頂したか。
+		CFLAG = 0x09 | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __CAN_FORBID__,//フラグ。
+		JUEL = 0x0A | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __CAN_FORBID__,//珠。PALAM.CSV
+		RELATION = 0x0B | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __CAN_FORBID__,//関係。indexは登録番号ではなくキャラ番号
+		EQUIP = 0x0C | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __CAN_FORBID__,//未使用変数
+		TEQUIP = 0x0D | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __CAN_FORBID__,//調教中パラメータ。アイテムを使用中か。ITEM.CSV
+		STAIN = 0x0E | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__,//調教中パラメータ。汚れ
+		GOTJUEL = 0x0F | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __CAN_FORBID__,//調教中パラメータ。今回獲得した珠。PALAM.CSV
+		NOWEX = 0x10 | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __CAN_FORBID__,//調教中パラメータ。直前のコマンドでどこで何回絶頂したか。
+        DOWNBASE = 0x11 | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __SAVE_EXTENDED__ | __EXTENDED__ | __CAN_FORBID__, //調教中パラメータ。LOSEBASEのキャラクタ変数版
+        CUP = 0x12 | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __SAVE_EXTENDED__ | __EXTENDED__ | __CAN_FORBID__,//調教中パラメータ。UPのキャラクタ変数版
+        CDOWN = 0x13 | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __SAVE_EXTENDED__ | __EXTENDED__ | __CAN_FORBID__,//調教中パラメータ。DOWNのキャラクタ変数版
+        TCVAR = 0x14 | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __SAVE_EXTENDED__ | __EXTENDED__ | __CAN_FORBID__,//キャラクタ変数での一時変数
+
+
+		__COUNT_SAVE_CHARACTER_INTEGER_ARRAY__ = 0x11,
+		__COUNT_CHARACTER_INTEGER_ARRAY__ = 0x54,
+
+		NAME = 0x00 | __STRING__ | __CHARACTER_DATA__,//名前//登録番号で呼び出す
+		CALLNAME = 0x01 | __STRING__ | __CHARACTER_DATA__,//呼び名
+		NICKNAME = 0x02 | __STRING__ | __CHARACTER_DATA__ | __SAVE_EXTENDED__ | __EXTENDED__,//あだ名
+		MASTERNAME = 0x03 | __STRING__ | __CHARACTER_DATA__ | __SAVE_EXTENDED__ | __EXTENDED__,//あだ名
+
+		__COUNT_SAVE_CHARACTER_STRING__ = 0x02,
+		__COUNT_CHARACTER_STRING__ = 0x04,
+
+		CSTR = 0x00 | __STRING__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __SAVE_EXTENDED__ | __EXTENDED__ | __CAN_FORBID__,//キャラクタ用文字列配列
+
+		__COUNT_SAVE_CHARACTER_STRING_ARRAY__ = 0x00,
+		__COUNT_CHARACTER_STRING_ARRAY__ = 0x01,
+
+		CDFLAG = 0x00 | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_2D__ | __SAVE_EXTENDED__ | __EXTENDED__ | __CAN_FORBID__,
+
+		__COUNT_CHARACTER_INTEGER_ARRAY_2D__ = 0x01,
+
+		__COUNT_CHARACTER_STRING_ARRAY_2D__ = 0x00,
+
+
+		DITEMTYPE = 0x00 | __INTEGER__ | __ARRAY_2D__ | __SAVE_EXTENDED__ | __EXTENDED__ | __CAN_FORBID__,
+		DA = 0x01 | __INTEGER__ | __ARRAY_2D__ | __SAVE_EXTENDED__ | __EXTENDED__ | __CAN_FORBID__,
+		DB = 0x02 | __INTEGER__ | __ARRAY_2D__ | __SAVE_EXTENDED__ | __EXTENDED__ | __CAN_FORBID__,
+		DC = 0x03 | __INTEGER__ | __ARRAY_2D__ | __SAVE_EXTENDED__ | __EXTENDED__ | __CAN_FORBID__,
+		DD = 0x04 | __INTEGER__ | __ARRAY_2D__ | __SAVE_EXTENDED__ | __EXTENDED__ | __CAN_FORBID__,
+		DE = 0x05 | __INTEGER__ | __ARRAY_2D__ | __SAVE_EXTENDED__ | __EXTENDED__ | __CAN_FORBID__,
+        __COUNT_INTEGER_ARRAY_2D__ = 0x06,
+
+		__COUNT_STRING_ARRAY_2D__ = 0x00,
+
+		TA = 0x00 | __INTEGER__ | __ARRAY_3D__ | __SAVE_EXTENDED__ | __EXTENDED__ | __CAN_FORBID__,
+        TB = 0x01 | __INTEGER__ | __ARRAY_3D__ | __SAVE_EXTENDED__ | __EXTENDED__ | __CAN_FORBID__,
+        __COUNT_INTEGER_ARRAY_3D__ = 0x02,
+
+        __COUNT_STRING_ARRAY_3D__ = 0x00,
+
+		//CALCな変数については番号順はどうでもいい。
+		//1803beta004 ~~NAME系については番号順をConstantDataが使用するので重要
+		
+		RAND = 0x00 | __INTEGER__ | __ARRAY_1D__ | __CALC__ | __UNCHANGEABLE__,//乱数。0~引数-1までの値を返す。
+		CHARANUM = 0x01 | __INTEGER__ | __CALC__ | __UNCHANGEABLE__,//キャラクタ数。キャラクタ登録数を返す。
+
+		ABLNAME = 0x00 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __CONSTANT__ | __CAN_FORBID__,//能力。ABL.CSV//csvから読まれるデータは保存されない。変更不可
+		EXPNAME = 0x01 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __CONSTANT__ | __CAN_FORBID__,//経験。EXP.CSV
+		TALENTNAME = 0x02 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __CONSTANT__ | __CAN_FORBID__,//素質。TALENT.CSV
+		PALAMNAME = 0x03 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __CONSTANT__ | __CAN_FORBID__,//能力。PALAM.CSV
+		TRAINNAME = 0x04 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,//調教名。TRAIN.CSV
+		MARKNAME = 0x05 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __CONSTANT__ | __CAN_FORBID__,//刻印。MARK.CSV
+		ITEMNAME = 0x06 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __CONSTANT__ | __CAN_FORBID__,//アイテム。ITEM.CSV
+		BASENAME = 0x07 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,//基礎能力名。BASE.CSV
+		SOURCENAME = 0x08 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,//調教ソース名。SOURCE.CSV
+		EXNAME = 0x09 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,//絶頂名。EX.CSV
+		__DUMMY_STR__ = 0x0A | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__,
+		EQUIPNAME = 0x0B | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,//装着物名。EQUIP.CSV
+		TEQUIPNAME = 0x0C | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,//調教時装着物名。TEQUIP.CSV
+		FLAGNAME = 0x0D | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,//フラグ名。FLAG.CSV
+		TFLAGNAME = 0x0E | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,//一時フラグ名。TFLAG.CSV
+		CFLAGNAME = 0x0F | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,//キャラクタフラグ名。CFLAG.CSV
+		TCVARNAME = 0x10 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,
+		CSTRNAME = 0x11 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,
+		STAINNAME = 0x12 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,
+
+		CDFLAGNAME1 = 0x13 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,
+		CDFLAGNAME2 = 0x14 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,
+		STRNAME = 0x15 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,
+		TSTRNAME = 0x16 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,
+		SAVESTRNAME = 0x17 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,
+		GLOBALNAME = 0x18 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,
+		GLOBALSNAME = 0x19 | __STRING__ | __ARRAY_1D__ | __UNCHANGEABLE__ | __EXTENDED__ | __CONSTANT__ | __CAN_FORBID__,
+
+        __COUNT_CSV_STRING_ARRAY_1D__ = 0x1A,
+
+
+		GAMEBASE_AUTHER = 0x04 | __STRING__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//文字列型。作者。綴りを間違えていたが互換性のため残す。
+		GAMEBASE_AUTHOR = 0x00 | __STRING__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//文字列型。作者
+		GAMEBASE_INFO = 0x01 | __STRING__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//文字列型。追加情報
+		GAMEBASE_YEAR = 0x02 | __STRING__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//文字列型。製作年
+		GAMEBASE_TITLE = 0x03 | __STRING__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//文字列型。タイトル
+		WINDOW_TITLE = 0x05 | __STRING__ | __CALC__ | __EXTENDED__,//文字列型。ウインドウのタイトル。変更可能。
+		//アンダースコア2つで囲まれた変数を追加したらVariableTokenに特別な処理が必要。
+		__FILE__ = 0x06 | __STRING__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//現在実行中のファイル名
+		__FUNCTION__ = 0x07 | __STRING__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//現在実行中の関数名
+        MONEYLABEL = 0x08 | __STRING__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//お金のラベル
+        DRAWLINESTR = 0x09 | __STRING__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//DRAWLINEの描画文字列
+        EMUERA_VERSION = 0x0A | __STRING__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__, //Emeuraのバージョン
+
+		LASTLOAD_TEXT = 0x05 | __STRING__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//数値型。
+
+		GAMEBASE_GAMECODE = 0x00 | __INTEGER__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//数値型。コード
+		GAMEBASE_VERSION = 0x01 | __INTEGER__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//数値型。バージョン
+		GAMEBASE_ALLOWVERSION = 0x02 | __INTEGER__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//数値型。バージョン違い認める
+		GAMEBASE_DEFAULTCHARA = 0x03 | __INTEGER__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//数値型。最初からいるキャラ
+		GAMEBASE_NOITEM = 0x04 | __INTEGER__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//数値型。アイテムなし
+
+		LASTLOAD_VERSION = 0x05 | __INTEGER__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//数値型。
+		LASTLOAD_NO = 0x06 | __INTEGER__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//数値型。
+		__LINE__ = 0x07 | __INTEGER__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//現在実行中の行番号
+		LINECOUNT = 0x08 | __INTEGER__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//描画した行の総数。CLEARで減少
+        ISTIMEOUT = 0x0B | __INT_MAX__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//TINPUT系等がTIMEOUTしたか?
+
+        __INT_MAX__ = 0x09 | __INTEGER__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//Int64最大値
+        __INT_MIN__ = 0x0A | __INTEGER__ | __CALC__ | __UNCHANGEABLE__ | __EXTENDED__,//Int64最小値
+
+		CVAR = 0xFC | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __EXTENDED__,//ユーザー定義変数
+		CVARS = 0xFC | __STRING__ | __CHARACTER_DATA__ | __ARRAY_1D__ | __EXTENDED__,//ユーザー定義変数
+		CVAR2D = 0xFC | __INTEGER__ | __CHARACTER_DATA__ | __ARRAY_2D__ | __EXTENDED__,//ユーザー定義変数
+		CVARS2D = 0xFC | __STRING__ | __CHARACTER_DATA__ | __ARRAY_2D__ | __EXTENDED__,//ユーザー定義変数
+		//CVAR3D = 0xFC | __INTEGER__ | __ARRAY_3D__ | __EXTENDED__,//ユーザー定義変数
+		//CVARS3D = 0xFC | __STRING__ | __ARRAY_3D__ | __EXTENDED__,//ユーザー定義変数
+		REF = 0xFD | __INTEGER__ | __ARRAY_1D__ | __EXTENDED__,//参照型
+		REFS = 0xFD | __STRING__ | __ARRAY_1D__ | __EXTENDED__,
+		REF2D = 0xFD | __INTEGER__ | __ARRAY_2D__ | __EXTENDED__,
+		REFS2D = 0xFD | __STRING__ | __ARRAY_2D__ | __EXTENDED__,
+		REF3D = 0xFD | __INTEGER__ | __ARRAY_3D__ | __EXTENDED__,
+		REFS3D = 0xFD | __STRING__ | __ARRAY_3D__ | __EXTENDED__,
+		VAR = 0xFE | __INTEGER__ | __ARRAY_1D__ | __EXTENDED__,//ユーザー定義変数 1808 プライベート変数と広域変数を区別しない
+		VARS = 0xFE | __STRING__ | __ARRAY_1D__ | __EXTENDED__,//ユーザー定義変数
+		VAR2D = 0xFE | __INTEGER__ | __ARRAY_2D__ | __EXTENDED__,//ユーザー定義変数
+		VARS2D = 0xFE | __STRING__ | __ARRAY_2D__ | __EXTENDED__,//ユーザー定義変数
+		VAR3D = 0xFE | __INTEGER__ | __ARRAY_3D__ | __EXTENDED__,//ユーザー定義変数
+		VARS3D = 0xFE | __STRING__ | __ARRAY_3D__ | __EXTENDED__//ユーザー定義変数
+		//PRIVATE = 0xFF | __INTEGER__ | __ARRAY_1D__ | __EXTENDED__,//プライベート変数
+		//PRIVATES = 0xFF | __STRING__ | __ARRAY_1D__ | __EXTENDED__,//プライベート変数
+		//PRIVATE2D = 0xFF | __INTEGER__ | __ARRAY_2D__ | __EXTENDED__,//プライベート変数
+		//PRIVATES2D = 0xFF | __STRING__ | __ARRAY_2D__ | __EXTENDED__,//プライベート変数
+		//PRIVATE3D = 0xFF | __INTEGER__ | __ARRAY_3D__ | __EXTENDED__,//プライベート変数
+		//PRIVATES3D = 0xFF | __STRING__ | __ARRAY_3D__ | __EXTENDED__,//プライベート変数
+	}
+}
+

+ 1111 - 0
NTERA/Game/GameData/Variable/VariableData.cs

@@ -0,0 +1,1111 @@
+using System;
+using System.Collections.Generic;
+using MinorShift.Emuera.GameProc;
+using MinorShift.Emuera.Sub;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera.GameData.Variable
+{
+	/// <summary>
+	/// 変数全部
+	/// </summary>
+	internal sealed partial class VariableData : IDisposable
+	{
+
+		readonly Int64[] dataInteger;
+		readonly string[] dataString;
+		readonly Int64[][] dataIntegerArray;
+		readonly string[][] dataStringArray;
+		readonly Int64[][,] dataIntegerArray2D;
+		readonly string[][,] dataStringArray2D;
+		readonly Int64[][, ,] dataIntegerArray3D;
+		readonly string[][, ,] dataStringArray3D;
+		//readonly VariableLocal<Int64, Int64Calculator> localVars;
+		//readonly VariableLocal<string, StringCalculator> localString;
+		//readonly VariableLocal<Int64, Int64Calculator> argVars;
+		//readonly VariableLocal<string, StringCalculator> argString;
+		readonly List<CharacterData> characterList;
+		public Int64[] DataInteger => dataInteger;
+		public string[] DataString => dataString;
+		public Int64[][] DataIntegerArray => dataIntegerArray;
+		public string[][] DataStringArray => dataStringArray;
+		public Int64[][,] DataIntegerArray2D => dataIntegerArray2D;
+		public string[][,] DataStringArray2D => dataStringArray2D;
+		public Int64[][, ,] DataIntegerArray3D => dataIntegerArray3D;
+
+		public string[][, ,] DataStringArray3D => dataStringArray3D;
+
+		//public VariableLocal<Int64, Int64Calculator> LocalVars { get { return localVars; } }
+		//public VariableLocal<string, StringCalculator> LocalString { get { return localString; } }
+		//public VariableLocal<Int64, Int64Calculator> ArgVars { get { return argVars; } }
+		//public VariableLocal<string, StringCalculator> ArgString { get { return argString; } }
+		public List<CharacterData> CharacterList => characterList;
+		readonly GameBase gamebase;
+		readonly ConstantData constant;
+		internal GameBase GameBase => gamebase;
+		internal ConstantData Constant => constant;
+
+		public Int64 LastLoadVersion = -1;
+		public Int64 LastLoadNo = -1;
+		public string LastLoadText = "";
+
+		Dictionary<string, VariableToken> varTokenDic = new Dictionary<string, VariableToken>();
+		Dictionary<string, VariableLocal> localvarTokenDic = new Dictionary<string, VariableLocal>();
+
+		/// <summary>
+		/// ユーザー変数のうちStaticかつ非Globalなもの。ERHでのDIM(非GLOBAL) と関数でのDIM (STATIC)の両方。ロードやリセットで初期化が必要。キャラクタ変数は除く。
+		/// </summary>
+		List<UserDefinedVariableToken> userDefinedStaticVarList = new List<UserDefinedVariableToken>();
+		/// <summary>
+		/// ユーザー広域変数のうちグローバル属性持ち。
+		/// </summary>
+		List<UserDefinedVariableToken> userDefinedGlobalVarList = new List<UserDefinedVariableToken>();
+		/// <summary>
+		/// ユーザー広域変数のうちセーブされるもの。グローバル、キャラクタ変数は除く。
+		/// </summary>
+		List<UserDefinedVariableToken>[] userDefinedSaveVarList = new List<UserDefinedVariableToken>[6];
+		/// <summary>
+		/// ユーザー広域変数のうち、グローバルかつセーブされるもの。
+		/// </summary>
+		List<UserDefinedVariableToken>[] userDefinedGlobalSaveVarList = new List<UserDefinedVariableToken>[6];
+		/// <summary>
+		/// ユーザー広域変数のうち、キャラクタ変数であるもの。初期化やセーブされるかどうかはCharacterDataの方で判断。
+		/// </summary>
+		public List<UserDefinedCharaVariableToken> UserDefinedCharaVarList = new List<UserDefinedCharaVariableToken>();
+
+		public VariableData(GameBase gamebase, ConstantData constant)
+		{
+			this.gamebase = gamebase;
+			this.constant = constant;
+			characterList = new List<CharacterData>();
+			//localVars = new VariableLocal<Int64, Int64Calculator>(constant.VariableIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.LOCAL)]);
+			//localString = new VariableLocal<string, StringCalculator>(constant.VariableStrArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.LOCALS)]);
+			//argVars = new VariableLocal<Int64, Int64Calculator>(constant.VariableIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.ARG)]);
+			//argString = new VariableLocal<string, StringCalculator>(constant.VariableStrArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.ARGS)]);
+			dataInteger = new Int64[(int)VariableCode.__COUNT_INTEGER__];
+
+			dataIntegerArray = new Int64[(int)VariableCode.__COUNT_INTEGER_ARRAY__][];
+			for (int i = 0; i < dataIntegerArray.Length; i++)
+				dataIntegerArray[i] = new Int64[constant.VariableIntArrayLength[i]];
+
+			dataString = new string[(int)VariableCode.__COUNT_STRING__];
+
+			dataStringArray = new string[(int)VariableCode.__COUNT_STRING_ARRAY__][];
+
+			for (int i = 0; i < dataStringArray.Length; i++)
+				dataStringArray[i] = new string[constant.VariableStrArrayLength[i]];
+
+
+			dataIntegerArray2D = new Int64[(int)VariableCode.__COUNT_INTEGER_ARRAY_2D__][,];
+			for (int i = 0; i < dataIntegerArray2D.Length; i++)
+			{
+				Int64 length64 = constant.VariableIntArray2DLength[i];
+				int length = (int)(length64 >> 32);
+				int length2 = (int)(length64 & 0x7FFFFFFF);
+				dataIntegerArray2D[i] = new Int64[length, length2];
+			}
+			dataStringArray2D = new string[(int)VariableCode.__COUNT_STRING_ARRAY_2D__][,];
+			for (int i = 0; i < dataStringArray2D.Length; i++)
+			{
+				Int64 length64 = constant.VariableStrArray2DLength[i];
+				int length = (int)(length64 >> 32);
+				int length2 = (int)(length64 & 0x7FFFFFFF);
+				dataStringArray2D[i] = new string[length, length2];
+			}
+			dataIntegerArray3D = new Int64[(int)VariableCode.__COUNT_INTEGER_ARRAY_3D__][, ,];
+			for (int i = 0; i < dataIntegerArray3D.Length; i++)
+			{
+				Int64 length64 = constant.VariableIntArray3DLength[i];
+				int length = (int)(length64 >> 40);
+				int length2 = (int)((length64 >> 20) & 0xFFFFF);
+				int length3 = (int)(length64 & 0xFFFFF);
+				dataIntegerArray3D[i] = new Int64[length, length2, length3];
+			}
+			dataStringArray3D = new string[(int)VariableCode.__COUNT_STRING_ARRAY_3D__][, ,];
+			for (int i = 0; i < dataStringArray3D.Length; i++)
+			{
+				Int64 length64 = constant.VariableStrArray3DLength[i];
+				int length = (int)(length64 >> 40);
+				int length2 = (int)((length64 >> 20) & 0xFFFFF);
+				int length3 = (int)(length64 & 0xFFFFF);
+				dataStringArray3D[i] = new string[length, length2, length3];
+			}
+			for (int i = 0; i < 6; i++)
+			{
+				userDefinedSaveVarList[i] = new List<UserDefinedVariableToken>();
+				userDefinedGlobalSaveVarList[i] = new List<UserDefinedVariableToken>();
+			}
+
+
+
+			SetDefaultValue(constant);
+
+			varTokenDic.Add("DAY", new Int1DVariableToken(VariableCode.DAY, this));
+			varTokenDic.Add("MONEY", new Int1DVariableToken(VariableCode.MONEY, this));
+			varTokenDic.Add("ITEM", new Int1DVariableToken(VariableCode.ITEM, this));
+			varTokenDic.Add("FLAG", new Int1DVariableToken(VariableCode.FLAG, this));
+			varTokenDic.Add("TFLAG", new Int1DVariableToken(VariableCode.TFLAG, this));
+			varTokenDic.Add("UP", new Int1DVariableToken(VariableCode.UP, this));
+			varTokenDic.Add("PALAMLV", new Int1DVariableToken(VariableCode.PALAMLV, this));
+			varTokenDic.Add("EXPLV", new Int1DVariableToken(VariableCode.EXPLV, this));
+			varTokenDic.Add("EJAC", new Int1DVariableToken(VariableCode.EJAC, this));
+			varTokenDic.Add("DOWN", new Int1DVariableToken(VariableCode.DOWN, this));
+			varTokenDic.Add("RESULT", new Int1DVariableToken(VariableCode.RESULT, this));
+			varTokenDic.Add("COUNT", new Int1DVariableToken(VariableCode.COUNT, this));
+			varTokenDic.Add("TARGET", new Int1DVariableToken(VariableCode.TARGET, this));
+			varTokenDic.Add("ASSI", new Int1DVariableToken(VariableCode.ASSI, this));
+			varTokenDic.Add("MASTER", new Int1DVariableToken(VariableCode.MASTER, this));
+			varTokenDic.Add("NOITEM", new Int1DVariableToken(VariableCode.NOITEM, this));
+			varTokenDic.Add("LOSEBASE", new Int1DVariableToken(VariableCode.LOSEBASE, this));
+			varTokenDic.Add("SELECTCOM", new Int1DVariableToken(VariableCode.SELECTCOM, this));
+			varTokenDic.Add("ASSIPLAY", new Int1DVariableToken(VariableCode.ASSIPLAY, this));
+			varTokenDic.Add("PREVCOM", new Int1DVariableToken(VariableCode.PREVCOM, this));
+			varTokenDic.Add("TIME", new Int1DVariableToken(VariableCode.TIME, this));
+			varTokenDic.Add("ITEMSALES", new Int1DVariableToken(VariableCode.ITEMSALES, this));
+			varTokenDic.Add("PLAYER", new Int1DVariableToken(VariableCode.PLAYER, this));
+			varTokenDic.Add("NEXTCOM", new Int1DVariableToken(VariableCode.NEXTCOM, this));
+			varTokenDic.Add("PBAND", new Int1DVariableToken(VariableCode.PBAND, this));
+			varTokenDic.Add("BOUGHT", new Int1DVariableToken(VariableCode.BOUGHT, this));
+			varTokenDic.Add("A", new Int1DVariableToken(VariableCode.A, this));
+			varTokenDic.Add("B", new Int1DVariableToken(VariableCode.B, this));
+			varTokenDic.Add("C", new Int1DVariableToken(VariableCode.C, this));
+			varTokenDic.Add("D", new Int1DVariableToken(VariableCode.D, this));
+			varTokenDic.Add("E", new Int1DVariableToken(VariableCode.E, this));
+			varTokenDic.Add("F", new Int1DVariableToken(VariableCode.F, this));
+			varTokenDic.Add("G", new Int1DVariableToken(VariableCode.G, this));
+			varTokenDic.Add("H", new Int1DVariableToken(VariableCode.H, this));
+			varTokenDic.Add("I", new Int1DVariableToken(VariableCode.I, this));
+			varTokenDic.Add("J", new Int1DVariableToken(VariableCode.J, this));
+			varTokenDic.Add("K", new Int1DVariableToken(VariableCode.K, this));
+			varTokenDic.Add("L", new Int1DVariableToken(VariableCode.L, this));
+			varTokenDic.Add("M", new Int1DVariableToken(VariableCode.M, this));
+			varTokenDic.Add("N", new Int1DVariableToken(VariableCode.N, this));
+			varTokenDic.Add("O", new Int1DVariableToken(VariableCode.O, this));
+			varTokenDic.Add("P", new Int1DVariableToken(VariableCode.P, this));
+			varTokenDic.Add("Q", new Int1DVariableToken(VariableCode.Q, this));
+			varTokenDic.Add("R", new Int1DVariableToken(VariableCode.R, this));
+			varTokenDic.Add("S", new Int1DVariableToken(VariableCode.S, this));
+			varTokenDic.Add("T", new Int1DVariableToken(VariableCode.T, this));
+			varTokenDic.Add("U", new Int1DVariableToken(VariableCode.U, this));
+			varTokenDic.Add("V", new Int1DVariableToken(VariableCode.V, this));
+			varTokenDic.Add("W", new Int1DVariableToken(VariableCode.W, this));
+			varTokenDic.Add("X", new Int1DVariableToken(VariableCode.X, this));
+			varTokenDic.Add("Y", new Int1DVariableToken(VariableCode.Y, this));
+			varTokenDic.Add("Z", new Int1DVariableToken(VariableCode.Z, this));
+
+			varTokenDic.Add("GLOBAL", new Int1DVariableToken(VariableCode.GLOBAL, this));
+			varTokenDic.Add("RANDDATA", new Int1DVariableToken(VariableCode.RANDDATA, this));
+
+			varTokenDic.Add("SAVESTR", new Str1DVariableToken(VariableCode.SAVESTR, this));
+			varTokenDic.Add("TSTR", new Str1DVariableToken(VariableCode.TSTR, this));
+			varTokenDic.Add("STR", new Str1DVariableToken(VariableCode.STR, this));
+			varTokenDic.Add("RESULTS", new Str1DVariableToken(VariableCode.RESULTS, this));
+			varTokenDic.Add("GLOBALS", new Str1DVariableToken(VariableCode.GLOBALS, this));
+
+			varTokenDic.Add("SAVEDATA_TEXT", new StrVariableToken(VariableCode.SAVEDATA_TEXT, this));
+
+			varTokenDic.Add("ISASSI", new CharaIntVariableToken(VariableCode.ISASSI, this));
+			varTokenDic.Add("NO", new CharaIntVariableToken(VariableCode.NO, this));
+
+			varTokenDic.Add("BASE", new CharaInt1DVariableToken(VariableCode.BASE, this));
+			varTokenDic.Add("MAXBASE", new CharaInt1DVariableToken(VariableCode.MAXBASE, this));
+			varTokenDic.Add("ABL", new CharaInt1DVariableToken(VariableCode.ABL, this));
+			varTokenDic.Add("TALENT", new CharaInt1DVariableToken(VariableCode.TALENT, this));
+			varTokenDic.Add("EXP", new CharaInt1DVariableToken(VariableCode.EXP, this));
+			varTokenDic.Add("MARK", new CharaInt1DVariableToken(VariableCode.MARK, this));
+			varTokenDic.Add("PALAM", new CharaInt1DVariableToken(VariableCode.PALAM, this));
+			varTokenDic.Add("SOURCE", new CharaInt1DVariableToken(VariableCode.SOURCE, this));
+			varTokenDic.Add("EX", new CharaInt1DVariableToken(VariableCode.EX, this));
+			varTokenDic.Add("CFLAG", new CharaInt1DVariableToken(VariableCode.CFLAG, this));
+			varTokenDic.Add("JUEL", new CharaInt1DVariableToken(VariableCode.JUEL, this));
+			varTokenDic.Add("RELATION", new CharaInt1DVariableToken(VariableCode.RELATION, this));
+			varTokenDic.Add("EQUIP", new CharaInt1DVariableToken(VariableCode.EQUIP, this));
+			varTokenDic.Add("TEQUIP", new CharaInt1DVariableToken(VariableCode.TEQUIP, this));
+			varTokenDic.Add("STAIN", new CharaInt1DVariableToken(VariableCode.STAIN, this));
+			varTokenDic.Add("GOTJUEL", new CharaInt1DVariableToken(VariableCode.GOTJUEL, this));
+			varTokenDic.Add("NOWEX", new CharaInt1DVariableToken(VariableCode.NOWEX, this));
+			varTokenDic.Add("DOWNBASE", new CharaInt1DVariableToken(VariableCode.DOWNBASE, this));
+			varTokenDic.Add("CUP", new CharaInt1DVariableToken(VariableCode.CUP, this));
+			varTokenDic.Add("CDOWN", new CharaInt1DVariableToken(VariableCode.CDOWN, this));
+			varTokenDic.Add("TCVAR", new CharaInt1DVariableToken(VariableCode.TCVAR, this));
+
+			varTokenDic.Add("NAME", new CharaStrVariableToken(VariableCode.NAME, this));
+			varTokenDic.Add("CALLNAME", new CharaStrVariableToken(VariableCode.CALLNAME, this));
+			varTokenDic.Add("NICKNAME", new CharaStrVariableToken(VariableCode.NICKNAME, this));
+			varTokenDic.Add("MASTERNAME", new CharaStrVariableToken(VariableCode.MASTERNAME, this));
+
+			varTokenDic.Add("CSTR", new CharaStr1DVariableToken(VariableCode.CSTR, this));
+
+			varTokenDic.Add("CDFLAG", new CharaInt2DVariableToken(VariableCode.CDFLAG, this));
+
+			varTokenDic.Add("DITEMTYPE", new Int2DVariableToken(VariableCode.DITEMTYPE, this));
+			varTokenDic.Add("DA", new Int2DVariableToken(VariableCode.DA, this));
+			varTokenDic.Add("DB", new Int2DVariableToken(VariableCode.DB, this));
+			varTokenDic.Add("DC", new Int2DVariableToken(VariableCode.DC, this));
+			varTokenDic.Add("DD", new Int2DVariableToken(VariableCode.DD, this));
+			varTokenDic.Add("DE", new Int2DVariableToken(VariableCode.DE, this));
+
+			varTokenDic.Add("TA", new Int3DVariableToken(VariableCode.TA, this));
+			varTokenDic.Add("TB", new Int3DVariableToken(VariableCode.TB, this));
+
+
+			varTokenDic.Add("ITEMPRICE", new Int1DConstantToken(VariableCode.ITEMPRICE, this, constant.ItemPrice));
+			varTokenDic.Add("ABLNAME", new Str1DConstantToken(VariableCode.ABLNAME, this, "Abl"));
+			varTokenDic.Add("TALENTNAME", new Str1DConstantToken(VariableCode.TALENTNAME, this, "Talent"));
+			varTokenDic.Add("EXPNAME", new Str1DConstantToken(VariableCode.EXPNAME, this, "Exp"));
+			varTokenDic.Add("MARKNAME", new Str1DConstantToken(VariableCode.MARKNAME, this, "Mark"));
+			varTokenDic.Add("PALAMNAME", new Str1DConstantToken(VariableCode.PALAMNAME, this, "Palam"));
+			varTokenDic.Add("ITEMNAME", new Str1DConstantToken(VariableCode.ITEMNAME, this, "Item"));
+			varTokenDic.Add("TRAINNAME", new Str1DConstantToken(VariableCode.TRAINNAME, this, "Train"));
+			varTokenDic.Add("BASENAME", new Str1DConstantToken(VariableCode.BASENAME, this, "Base"));
+			varTokenDic.Add("SOURCENAME", new Str1DConstantToken(VariableCode.SOURCENAME, this, "Source"));
+			varTokenDic.Add("EXNAME", new Str1DConstantToken(VariableCode.EXNAME, this, "Ex"));
+			varTokenDic.Add("EQUIPNAME", new Str1DConstantToken(VariableCode.EQUIPNAME, this,"EQUIP"));
+			varTokenDic.Add("TEQUIPNAME", new Str1DConstantToken(VariableCode.TEQUIPNAME, this, "TEQUIP"));
+			varTokenDic.Add("FLAGNAME", new Str1DConstantToken(VariableCode.FLAGNAME, this, "Flag"));
+			varTokenDic.Add("TFLAGNAME", new Str1DConstantToken(VariableCode.TFLAGNAME, this, "TFLAG"));
+			varTokenDic.Add("CFLAGNAME", new Str1DConstantToken(VariableCode.CFLAGNAME, this, "Cflag"));
+			varTokenDic.Add("TCVARNAME", new Str1DConstantToken(VariableCode.TCVARNAME, this, "Tcvar"));
+			varTokenDic.Add("CSTRNAME", new Str1DConstantToken(VariableCode.CSTRNAME, this, "CSTR"));
+			varTokenDic.Add("STAINNAME", new Str1DConstantToken(VariableCode.STAINNAME, this, "Stain"));
+
+			varTokenDic.Add("CDFLAGNAME1", new Str1DConstantToken(VariableCode.CDFLAGNAME1, this, "Cdflag1"));
+			varTokenDic.Add("CDFLAGNAME2", new Str1DConstantToken(VariableCode.CDFLAGNAME2, this, "Cdflag2"));
+			varTokenDic.Add("STRNAME", new Str1DConstantToken(VariableCode.STRNAME, this, "Str"));
+			varTokenDic.Add("TSTRNAME", new Str1DConstantToken(VariableCode.TSTRNAME, this, "TSTR"));
+			varTokenDic.Add("SAVESTRNAME", new Str1DConstantToken(VariableCode.SAVESTRNAME, this, "SaveStr"));
+			varTokenDic.Add("GLOBALNAME", new Str1DConstantToken(VariableCode.GLOBALNAME, this, "GLOBAL"));
+			varTokenDic.Add("GLOBALSNAME", new Str1DConstantToken(VariableCode.GLOBALSNAME, this, "GLOBALS"));
+
+			StrConstantToken token = new StrConstantToken(VariableCode.GAMEBASE_AUTHOR, this, gamebase.ScriptAutherName);
+			varTokenDic.Add("GAMEBASE_AUTHER", token);
+			varTokenDic.Add("GAMEBASE_AUTHOR", token);
+			varTokenDic.Add("GAMEBASE_INFO", new StrConstantToken(VariableCode.GAMEBASE_INFO, this, gamebase.ScriptDetail));
+			varTokenDic.Add("GAMEBASE_YEAR", new StrConstantToken(VariableCode.GAMEBASE_YEAR, this, gamebase.ScriptYear));
+			varTokenDic.Add("GAMEBASE_TITLE", new StrConstantToken(VariableCode.GAMEBASE_TITLE, this, gamebase.ScriptTitle));
+
+
+			varTokenDic.Add("GAMEBASE_GAMECODE", new IntConstantToken(VariableCode.GAMEBASE_GAMECODE, this, gamebase.ScriptUniqueCode));
+			varTokenDic.Add("GAMEBASE_VERSION", new IntConstantToken(VariableCode.GAMEBASE_VERSION, this, gamebase.ScriptVersion));
+			varTokenDic.Add("GAMEBASE_ALLOWVERSION", new IntConstantToken(VariableCode.GAMEBASE_ALLOWVERSION, this, gamebase.ScriptCompatibleMinVersion));
+			varTokenDic.Add("GAMEBASE_DEFAULTCHARA", new IntConstantToken(VariableCode.GAMEBASE_DEFAULTCHARA, this, gamebase.DefaultCharacter));
+			varTokenDic.Add("GAMEBASE_NOITEM", new IntConstantToken(VariableCode.GAMEBASE_NOITEM, this, gamebase.DefaultNoItem));
+
+		    VariableToken rand;
+			if (Config.CompatiRAND)
+				rand = new CompatiRandToken(VariableCode.RAND, this);
+			else
+				rand = new RandToken(VariableCode.RAND, this);
+			varTokenDic.Add("RAND", rand);
+			varTokenDic.Add("CHARANUM", new CHARANUM_Token(VariableCode.CHARANUM, this));
+
+
+			varTokenDic.Add("LASTLOAD_TEXT", new LASTLOAD_TEXT_Token(VariableCode.LASTLOAD_TEXT, this));
+			varTokenDic.Add("LASTLOAD_VERSION", new LASTLOAD_VERSION_Token(VariableCode.LASTLOAD_VERSION, this));
+			varTokenDic.Add("LASTLOAD_NO", new LASTLOAD_NO_Token(VariableCode.LASTLOAD_NO, this));
+			varTokenDic.Add("LINECOUNT", new LINECOUNT_Token(VariableCode.LINECOUNT, this));
+            varTokenDic.Add("ISTIMEOUT", new ISTIMEOUTToken(VariableCode.ISTIMEOUT, this));
+			varTokenDic.Add("__INT_MAX__", new __INT_MAX__Token(VariableCode.__INT_MAX__, this));
+			varTokenDic.Add("__INT_MIN__", new __INT_MIN__Token(VariableCode.__INT_MIN__, this));
+            varTokenDic.Add("EMUERA_VERSION", new EMUERA_VERSIONToken(VariableCode.EMUERA_VERSION, this));
+
+			varTokenDic.Add("WINDOW_TITLE", new WINDOW_TITLE_Token(VariableCode.WINDOW_TITLE, this));
+			varTokenDic.Add("MONEYLABEL", new MONEYLABEL_Token(VariableCode.MONEYLABEL, this));
+			varTokenDic.Add("DRAWLINESTR", new DRAWLINESTR_Token(VariableCode.DRAWLINESTR, this));
+			if (!Program.DebugMode)
+			{
+				varTokenDic.Add("__FILE__", new EmptyStrToken(VariableCode.__FILE__, this));
+				varTokenDic.Add("__FUNCTION__", new EmptyStrToken(VariableCode.__FUNCTION__, this));
+				varTokenDic.Add("__LINE__", new EmptyIntToken(VariableCode.__LINE__, this));
+			}
+			else
+			{
+				varTokenDic.Add("__FILE__", new Debug__FILE__Token(VariableCode.__FILE__, this));
+				varTokenDic.Add("__FUNCTION__", new Debug__FUNCTION__Token(VariableCode.__FUNCTION__, this));
+				varTokenDic.Add("__LINE__", new Debug__LINE__Token(VariableCode.__LINE__, this));
+			}
+
+			int size = constant.VariableIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.LOCAL)];
+			localvarTokenDic.Add("LOCAL", new VariableLocal(VariableCode.LOCAL, size, CreateLocalInt));
+			size = constant.VariableIntArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.ARG)];
+			localvarTokenDic.Add("ARG", new VariableLocal(VariableCode.ARG, size, CreateLocalInt));
+			size = constant.VariableStrArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.LOCALS)];
+			localvarTokenDic.Add("LOCALS", new VariableLocal(VariableCode.LOCALS, size, CreateLocalStr));
+			size = constant.VariableStrArrayLength[(int)(VariableCode.__LOWERCASE__ & VariableCode.ARGS)];
+			localvarTokenDic.Add("ARGS", new VariableLocal(VariableCode.ARGS, size, CreateLocalStr));
+
+		}
+
+		private LocalVariableToken CreateLocalInt(VariableCode varCode, string subKey, int size)
+		{
+			return new LocalInt1DVariableToken(varCode, this, subKey, size);
+		}
+		private LocalVariableToken CreateLocalStr(VariableCode varCode, string subKey, int size)
+		{
+			return new LocalStr1DVariableToken(varCode, this, subKey, size);
+		}
+		public Dictionary<string, VariableToken> GetVarTokenDicClone()
+		{
+			Dictionary<string, VariableToken> clone = new Dictionary<string, VariableToken>();
+			foreach (KeyValuePair<string, VariableToken> pair in varTokenDic)
+				clone.Add(pair.Key, pair.Value);
+			return clone;
+		}
+		public Dictionary<string, VariableToken> GetVarTokenDic()
+		{
+			return varTokenDic;
+		}
+		public Dictionary<string, VariableLocal> GetLocalvarTokenDic() { return localvarTokenDic; }
+		public VariableToken GetSystemVariableToken(string str)
+		{
+			return varTokenDic[str];
+		}
+
+
+		public UserDefinedCharaVariableToken CreateUserDefCharaVariable(UserDefinedVariableData data)
+		{
+			UserDefinedCharaVariableToken ret = null;
+			if (data.CharaData)
+			{
+				int index = UserDefinedCharaVarList.Count;
+				if (data.TypeIsStr)
+					switch (data.Dimension)
+					{
+						case 1: ret = new UserDefinedCharaStr1DVariableToken(data, this, index); break;
+						case 2: ret = new UserDefinedCharaStr2DVariableToken(data, this, index); break;
+						default: throw new ExeEE("異常な変数宣言");
+					}
+				else
+					switch (data.Dimension)
+					{
+						case 1: ret = new UserDefinedCharaInt1DVariableToken(data, this, index); break;
+						case 2: ret = new UserDefinedCharaInt2DVariableToken(data, this, index); break;
+						default: throw new ExeEE("異常な変数宣言");
+					}
+			}
+			UserDefinedCharaVarList.Add(ret);
+			return ret;
+		}
+		public UserDefinedVariableToken CreateUserDefVariable(UserDefinedVariableData data)
+		{
+			UserDefinedVariableToken ret = null;
+			if (data.TypeIsStr)
+				switch (data.Dimension)
+				{
+					case 1: ret = new StaticStr1DVariableToken(data); break;
+					case 2: ret = new StaticStr2DVariableToken(data); break;
+					case 3: ret = new StaticStr3DVariableToken(data); break;
+					default: throw new ExeEE("異常な変数宣言");
+				}
+			else
+				switch (data.Dimension)
+				{
+					case 1: ret = new StaticInt1DVariableToken(data); break;
+					case 2: ret = new StaticInt2DVariableToken(data); break;
+					case 3: ret = new StaticInt3DVariableToken(data); break;
+					default: throw new ExeEE("異常な変数宣言");
+				}
+			if (ret.IsGlobal)
+				userDefinedGlobalVarList.Add(ret);
+			else
+				userDefinedStaticVarList.Add(ret);
+			if (ret.IsSavedata)
+			{
+				int type = ret.Dimension * 2 - 2;
+				if (!ret.IsString)
+					type++;
+				if (ret.IsGlobal)
+					userDefinedGlobalSaveVarList[type].Add(ret);
+				else
+					userDefinedSaveVarList[type].Add(ret);
+			}
+			return ret;
+		}
+
+		public UserDefinedVariableToken CreatePrivateVariable(UserDefinedVariableData data)
+		{
+			UserDefinedVariableToken ret = null;
+			if (data.Reference)//参照型
+			{//すべて非Staticなはず
+				if (data.TypeIsStr)
+				{
+					switch (data.Dimension)
+					{
+						case 1: ret = new ReferenceStr1DToken(data); break;
+						case 2: ret = new ReferenceStr2DToken(data); break;
+						case 3: ret = new ReferenceStr3DToken(data); break;
+						default: throw new ExeEE("異常な変数宣言");
+					}
+				}
+				else
+				{
+					switch (data.Dimension)
+					{
+						case 1: ret = new ReferenceInt1DToken(data); break;
+						case 2: ret = new ReferenceInt2DToken(data); break;
+						case 3: ret = new ReferenceInt3DToken(data); break;
+						default: throw new ExeEE("異常な変数宣言");
+					}
+				}
+			}
+			else if (data.Static)
+			{
+				if (data.TypeIsStr)
+				{
+					switch (data.Dimension)
+					{
+						case 1: ret = new StaticStr1DVariableToken(data); break;
+						case 2: ret = new StaticStr2DVariableToken(data); break;
+						case 3: ret = new StaticStr3DVariableToken(data); break;
+						default: throw new ExeEE("異常な変数宣言");
+					}
+				}
+				else
+				{
+					switch (data.Dimension)
+					{
+						case 1: ret = new StaticInt1DVariableToken(data); break;
+						case 2: ret = new StaticInt2DVariableToken(data); break;
+						case 3: ret = new StaticInt3DVariableToken(data); break;
+						default: throw new ExeEE("異常な変数宣言");
+					}
+				}
+				userDefinedStaticVarList.Add(ret);
+			}
+			else
+			{
+				if (data.TypeIsStr)
+				{
+					switch (data.Dimension)
+					{
+						case 1: ret = new PrivateStr1DVariableToken(data); break;
+						case 2: ret = new PrivateStr2DVariableToken(data); break;
+						case 3: ret = new PrivateStr3DVariableToken(data); break;
+						default: throw new ExeEE("異常な変数宣言");
+					}
+				}
+				else
+				{
+					switch (data.Dimension)
+					{
+						case 1: ret = new PrivateInt1DVariableToken(data); break;
+						case 2: ret = new PrivateInt2DVariableToken(data); break;
+						case 3: ret = new PrivateInt3DVariableToken(data); break;
+						default: throw new ExeEE("異常な変数宣言");
+					}
+				}
+			}
+			return ret;
+		}
+
+		public void SetDefaultGlobalValue()
+		{
+
+			Int64[] globalInt = dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.GLOBAL];
+			string[] globalStr = dataStringArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.GLOBALS];
+			for (int i = 0; i < globalInt.Length; i++)
+				globalInt[i] = 0;
+			for (int i = 0; i < globalStr.Length; i++)
+				globalStr[i] = null;
+			foreach (UserDefinedVariableToken var in userDefinedGlobalVarList)
+				var.SetDefault();
+		}
+
+		public void SetDefaultLocalValue()
+		{
+			foreach (VariableLocal local in localvarTokenDic.Values)
+				local.SetDefault();
+			foreach (UserDefinedVariableToken var in userDefinedStaticVarList)
+				var.SetDefault();
+		}
+
+		public void ClearLocalValue()
+		{
+			foreach (VariableLocal local in localvarTokenDic.Values)
+				local.Clear();
+		}
+
+
+		/// <summary>
+		/// ローカルとグローバル以外初期化
+		/// </summary>
+		public void SetDefaultValue(ConstantData constant)
+		{
+
+			for (int i = 0; i < dataInteger.Length; i++)
+				dataInteger[i] = 0;
+
+			for (int i = 0; i < dataIntegerArray.Length; i++)
+			{
+				switch (i)
+				{
+					case (int)(VariableCode.__LOWERCASE__ & VariableCode.GLOBAL):
+						break;
+					case (int)(VariableCode.__LOWERCASE__ & VariableCode.ITEMPRICE):
+						//constant.ItemPrice.CopyTo(dataIntegerArray[i], 0);
+						Buffer.BlockCopy(constant.ItemPrice, 0, dataIntegerArray[i], 0, 8 * dataIntegerArray[i].Length);
+						break;
+					default:
+						for (int j = 0; j < dataIntegerArray[i].Length; j++)
+							dataIntegerArray[i][j] = 0;
+						break;
+				}
+			}
+
+			for (int i = 0; i < dataString.Length; i++)
+				dataString[i] = null;
+
+			for (int i = 0; i < dataStringArray.Length; i++)
+			{
+				switch (i)
+				{
+					case (int)(VariableCode.__LOWERCASE__ & VariableCode.GLOBALS):
+						break;
+					case (int)(VariableCode.__LOWERCASE__ & VariableCode.STR):
+						{
+							string[] csvStrData = constant.GetCsvNameList(VariableCode.__DUMMY_STR__);
+							csvStrData.CopyTo(dataStringArray[i], 0);
+							break;
+						}
+					default:
+						for (int j = 0; j < dataStringArray[i].Length; j++)
+							dataStringArray[i][j] = null;
+						break;
+				}
+			}
+			for (int i = 0; i < dataIntegerArray2D.Length; i++)
+			{
+				Int64[,] array2D = dataIntegerArray2D[i];
+				int length0 = array2D.GetLength(0);
+				int length1 = array2D.GetLength(1);
+				for (int x = 0; x < length0; x++)
+					for (int y = 0; y < length1; y++)
+						array2D[x, y] = 0;
+			}
+			for (int i = 0; i < dataStringArray2D.Length; i++)
+			{
+				string[,] array2D = dataStringArray2D[i];
+				int length0 = array2D.GetLength(0);
+				int length1 = array2D.GetLength(1);
+				for (int x = 0; x < length0; x++)
+					for (int y = 0; y < length1; y++)
+						array2D[x, y] = null;
+			}
+			for (int i = 0; i < dataIntegerArray3D.Length; i++)
+			{
+				Int64[, ,] array3D = dataIntegerArray3D[i];
+				int length0 = array3D.GetLength(0);
+				int length1 = array3D.GetLength(1);
+				int length2 = array3D.GetLength(2);
+				for (int x = 0; x < length0; x++)
+					for (int y = 0; y < length1; y++)
+						for (int z = 0; z < length2; z++)
+							array3D[x, y, z] = 0;
+			}
+			for (int i = 0; i < dataStringArray3D.Length; i++)
+			{
+				string[, ,] array3D = dataStringArray3D[i];
+				int length0 = array3D.GetLength(0);
+				int length1 = array3D.GetLength(1);
+				int length2 = array3D.GetLength(2);
+				for (int x = 0; x < length0; x++)
+					for (int y = 0; y < length1; y++)
+						for (int z = 0; z < length2; z++)
+							array3D[x, y, z] = null;
+			}
+
+			Int64[] palamlv = dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.PALAMLV];
+			List<Int64> defPalam = Config.PalamLvDef;
+			defPalam.CopyTo(0, palamlv, 0, Math.Min(palamlv.Length, defPalam.Count));
+			//palamlv[0] = 0;
+			//palamlv[1] = 100;
+			//palamlv[2] = 500;
+			//palamlv[3] = 3000;
+			//palamlv[4] = 10000;
+			//palamlv[5] = 30000;
+			//palamlv[6] = 60000;
+			//palamlv[7] = 100000;
+			//palamlv[8] = 150000;
+			//palamlv[9] = 250000;
+
+			Int64[] explv = dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.EXPLV];
+			List<Int64> defExpLv = Config.ExpLvDef;
+			defExpLv.CopyTo(0, explv, 0, Math.Min(explv.Length, defExpLv.Count));
+			//explv[0] = 0;
+			//explv[1] = 1;
+			//explv[2] = 4;
+			//explv[3] = 20;
+			//explv[4] = 50;
+			//explv[5] = 200;
+
+			//dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.ASSIPLAY][0] = 0;
+			//dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.MASTER][0] = 0;
+			long[] array;
+			array = dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.ASSI];
+			if (array.Length > 0) array[0] = -1;
+			array = dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.TARGET];
+			if (array.Length > 0) array[0] = 1;
+			array = dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.PBAND];
+			if (array.Length > 0) array[0] = Config.PbandDef;
+			array = dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.EJAC];
+			if (array.Length > 0) array[0] = 10000;
+
+			LastLoadVersion = -1;
+			LastLoadNo = -1;
+			LastLoadText = "";
+		}
+
+
+		const int strCount = (int)VariableCode.__COUNT_SAVE_STRING__;
+		const int intCount = (int)VariableCode.__COUNT_SAVE_INTEGER__;
+		const int intArrayCount = (int)VariableCode.__COUNT_SAVE_INTEGER_ARRAY__;
+		const int strArrayCount = (int)VariableCode.__COUNT_SAVE_STRING_ARRAY__;
+		public void SaveToStream(EraDataWriter writer)
+		{
+
+			for (int i = 0; i < strCount; i++)
+				writer.Write(dataString[i]);
+			for (int i = 0; i < intCount; i++)
+				writer.Write(dataInteger[i]);
+			for (int i = 0; i < intArrayCount; i++)
+				writer.Write(dataIntegerArray[i]);
+			for (int i = 0; i < strArrayCount; i++)
+				writer.Write(dataStringArray[i]);
+		}
+
+		public void LoadFromStream(EraDataReader reader)
+		{
+
+			for (int i = 0; i < strCount; i++)
+				dataString[i] = reader.ReadString();
+			for (int i = 0; i < intCount; i++)
+				dataInteger[i] = reader.ReadInt64();
+			for (int i = 0; i < intArrayCount; i++)
+				reader.ReadInt64Array(dataIntegerArray[i]);
+			for (int i = 0; i < strArrayCount; i++)
+				reader.ReadStringArray(dataStringArray[i]);
+		}
+
+		public void SaveToStreamExtended(EraDataWriter writer)
+		{
+			List<VariableCode> codeList = null;
+
+			//dataString
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__STRING__);
+			foreach (VariableCode code in codeList)
+				writer.WriteExtended(code.ToString(), dataString[(int)VariableCode.__LOWERCASE__ & (int)code]);
+			writer.EmuSeparete();
+
+			//datainteger
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__INTEGER__);
+			foreach (VariableCode code in codeList)
+				writer.WriteExtended(code.ToString(), dataInteger[(int)VariableCode.__LOWERCASE__ & (int)code]);
+			writer.EmuSeparete();
+
+			//dataStringArray
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__ARRAY_1D__ | VariableCode.__STRING__);
+			foreach (VariableCode code in codeList)
+				writer.WriteExtended(code.ToString(), dataStringArray[(int)VariableCode.__LOWERCASE__ & (int)code]);
+			writer.EmuSeparete();
+
+			//dataIntegerArray
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__ARRAY_1D__ | VariableCode.__INTEGER__);
+			foreach (VariableCode code in codeList)
+				writer.WriteExtended(code.ToString(), dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)code]);
+			writer.EmuSeparete();
+
+			//dataStringArray2D
+			//StringArray2Dの保存は未実装
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__ARRAY_2D__ | VariableCode.__STRING__);
+			foreach (VariableCode code in codeList)
+				writer.WriteExtended(code.ToString(), dataStringArray2D[(int)VariableCode.__LOWERCASE__ & (int)code]);
+			writer.EmuSeparete();
+
+			//dataIntegerArray2D
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__ARRAY_2D__ | VariableCode.__INTEGER__);
+			foreach (VariableCode code in codeList)
+				writer.WriteExtended(code.ToString(), dataIntegerArray2D[(int)VariableCode.__LOWERCASE__ & (int)code]);
+			writer.EmuSeparete();
+
+			//dataStringArray3D
+			//StringArray3Dの保存は未実装
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__ARRAY_3D__ | VariableCode.__STRING__);
+			foreach (VariableCode code in codeList)
+				writer.WriteExtended(code.ToString(), dataStringArray3D[(int)VariableCode.__LOWERCASE__ & (int)code]);
+			writer.EmuSeparete();
+
+			//dataIntegerArray3D
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__ARRAY_3D__ | VariableCode.__INTEGER__);
+			foreach (VariableCode code in codeList)
+				writer.WriteExtended(code.ToString(), dataIntegerArray3D[(int)VariableCode.__LOWERCASE__ & (int)code]);
+			writer.EmuSeparete();
+
+			for (int i = 0; i < 6; i++)
+			{
+				foreach (UserDefinedVariableToken var in userDefinedSaveVarList[i])
+				{
+					//if (!var.IsSavedata) continue;
+					switch (i)
+					{
+						case 0: writer.WriteExtended(var.Name, (string[])var.GetArray()); break;
+						case 1: writer.WriteExtended(var.Name, (Int64[])var.GetArray()); break;
+						case 2: writer.WriteExtended(var.Name, (string[,])var.GetArray()); break;
+						case 3: writer.WriteExtended(var.Name, (Int64[,])var.GetArray()); break;
+						case 4: writer.WriteExtended(var.Name, (string[, ,])var.GetArray()); break;
+						case 5: writer.WriteExtended(var.Name, (Int64[, ,])var.GetArray()); break;
+					}
+				}
+				writer.EmuSeparete();
+			}
+		}
+
+
+		public void LoadFromStreamExtended(EraDataReader reader, int version)
+		{
+			Dictionary<string, string> strDic = reader.ReadStringExtended();
+			Dictionary<string, Int64> intDic = reader.ReadInt64Extended();
+			Dictionary<string, List<string>> strListDic = reader.ReadStringArrayExtended();
+			Dictionary<string, List<Int64>> intListDic = reader.ReadInt64ArrayExtended();
+			Dictionary<string, List<string[]>> str2DListDic = reader.ReadStringArray2DExtended();
+			Dictionary<string, List<Int64[]>> int2DListDic = reader.ReadInt64Array2DExtended();
+			Dictionary<string, List<List<string[]>>> str3DListDic = reader.ReadStringArray3DExtended();
+			Dictionary<string, List<List<Int64[]>>> int3DListDic = reader.ReadInt64Array3DExtended();
+			List<VariableCode> codeList = null;
+
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__STRING__);
+			foreach (VariableCode code in codeList)
+				if (strDic.ContainsKey(code.ToString()))
+					dataString[(int)VariableCode.__LOWERCASE__ & (int)code] = strDic[code.ToString()];
+
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__INTEGER__);
+			foreach (VariableCode code in codeList)
+				if (intDic.ContainsKey(code.ToString()))
+					dataInteger[(int)VariableCode.__LOWERCASE__ & (int)code] = intDic[code.ToString()];
+
+
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__ARRAY_1D__ | VariableCode.__STRING__);
+			foreach (VariableCode code in codeList)
+				if (strListDic.ContainsKey(code.ToString()))
+					copyListToArray(strListDic[code.ToString()], dataStringArray[(int)VariableCode.__LOWERCASE__ & (int)code]);
+
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__ARRAY_1D__ | VariableCode.__INTEGER__);
+			foreach (VariableCode code in codeList)
+				if (intListDic.ContainsKey(code.ToString()))
+					copyListToArray(intListDic[code.ToString()], dataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)code]);
+
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__ARRAY_2D__ | VariableCode.__STRING__);
+			foreach (VariableCode code in codeList)
+				if (str2DListDic.ContainsKey(code.ToString()))
+					copyListToArray2D(str2DListDic[code.ToString()], dataStringArray2D[(int)VariableCode.__LOWERCASE__ & (int)code]);
+
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__ARRAY_2D__ | VariableCode.__INTEGER__);
+			foreach (VariableCode code in codeList)
+				if (int2DListDic.ContainsKey(code.ToString()))
+					copyListToArray2D(int2DListDic[code.ToString()], dataIntegerArray2D[(int)VariableCode.__LOWERCASE__ & (int)code]);
+
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__ARRAY_3D__ | VariableCode.__STRING__);
+			foreach (VariableCode code in codeList)
+				if (str3DListDic.ContainsKey(code.ToString()))
+					copyListToArray3D(str3DListDic[code.ToString()], dataStringArray3D[(int)VariableCode.__LOWERCASE__ & (int)code]);
+
+			codeList = VariableIdentifier.GetExtSaveList(VariableCode.__ARRAY_3D__ | VariableCode.__INTEGER__);
+			foreach (VariableCode code in codeList)
+				if (int3DListDic.ContainsKey(code.ToString()))
+					copyListToArray3D(int3DListDic[code.ToString()], dataIntegerArray3D[(int)VariableCode.__LOWERCASE__ & (int)code]);
+
+			if (version < 1808)//ユーザー定義変数の保存の実装前
+				return;
+
+			strListDic = reader.ReadStringArrayExtended();
+			intListDic = reader.ReadInt64ArrayExtended();
+			str2DListDic = reader.ReadStringArray2DExtended();
+			int2DListDic = reader.ReadInt64Array2DExtended();
+			str3DListDic = reader.ReadStringArray3DExtended();
+			int3DListDic = reader.ReadInt64Array3DExtended();
+			List<UserDefinedVariableToken> varList = null;
+
+			int i = 0;
+			varList = userDefinedSaveVarList[i]; i++;
+			foreach (UserDefinedVariableToken var in varList)
+				if (strListDic.ContainsKey(var.Name))
+					copyListToArray(strListDic[var.Name], (string[])var.GetArray());
+
+			varList = userDefinedSaveVarList[i]; i++;
+			foreach (UserDefinedVariableToken var in varList)
+				if (intListDic.ContainsKey(var.Name))
+					copyListToArray(intListDic[var.Name], (Int64[])var.GetArray());
+
+			varList = userDefinedSaveVarList[i]; i++;
+			foreach (UserDefinedVariableToken var in varList)
+				if (str2DListDic.ContainsKey(var.Name))
+					copyListToArray2D(str2DListDic[var.Name], (string[,])var.GetArray());
+
+			varList = userDefinedSaveVarList[i]; i++;
+			foreach (UserDefinedVariableToken var in varList)
+				if (int2DListDic.ContainsKey(var.Name))
+					copyListToArray2D(int2DListDic[var.Name], (Int64[,])var.GetArray());
+
+			varList = userDefinedSaveVarList[i]; i++;
+			foreach (UserDefinedVariableToken var in varList)
+				if (str3DListDic.ContainsKey(var.Name))
+					copyListToArray3D(str3DListDic[var.Name], (string[, ,])var.GetArray());
+
+			varList = userDefinedSaveVarList[i]; i++;
+			foreach (UserDefinedVariableToken var in varList)
+				if (int3DListDic.ContainsKey(var.Name))
+					copyListToArray3D(int3DListDic[var.Name], (Int64[, ,])var.GetArray());
+		}
+
+		private void copyListToArray<T>(List<T> srcList, T[] destArray)
+		{
+			int count = Math.Min(srcList.Count, destArray.Length);
+			for (int i = 0; i < count; i++)
+			{
+				destArray[i] = srcList[i];
+			}
+		}
+
+		private void copyListToArray2D<T>(List<T[]> srcList, T[,] destArray)
+		{
+			int countX = Math.Min(srcList.Count, destArray.GetLength(0));
+			int dLength = destArray.GetLength(1);
+			for (int x = 0; x < countX; x++)
+			{
+				T[] srcArray = srcList[x];
+				int countY = Math.Min(srcArray.Length, dLength);
+				for (int y = 0; y < countY; y++)
+				{
+					destArray[x, y] = srcArray[y];
+				}
+			}
+		}
+		private void copyListToArray3D<T>(List<List<T[]>> srcList, T[, ,] destArray)
+		{
+			int countX = Math.Min(srcList.Count, destArray.GetLength(0));
+			int dLength1 = destArray.GetLength(1);
+			int dLength2 = destArray.GetLength(2);
+			for (int x = 0; x < countX; x++)
+			{
+				List<T[]> srcArray = srcList[x];
+				int countY = Math.Min(srcArray.Count, dLength1);
+				for (int y = 0; y < countY; y++)
+				{
+					T[] baseArray = srcArray[y];
+					int countZ = Math.Min(baseArray.Length, dLength2);
+					for (int z = 0; z < countZ; z++)
+					{
+						destArray[x, y, z] = baseArray[z];
+					}
+				}
+			}
+		}
+
+
+		public void SaveGlobalToStream(EraDataWriter writer)
+		{
+			writer.Write(dataIntegerArray[(int)(VariableCode.__LOWERCASE__ & VariableCode.GLOBAL)]);
+			writer.Write(dataStringArray[(int)(VariableCode.__LOWERCASE__ & VariableCode.GLOBALS)]);
+		}
+
+		public void LoadGlobalFromStream(EraDataReader reader)
+		{
+			reader.ReadInt64Array(dataIntegerArray[(int)(VariableCode.__LOWERCASE__ & VariableCode.GLOBAL)]);
+			reader.ReadStringArray(dataStringArray[(int)(VariableCode.__LOWERCASE__ & VariableCode.GLOBALS)]);
+		}
+
+		public void SaveGlobalToStream1808(EraDataWriter writer)
+		{
+			for (int i = 0; i < 6; i++)
+			{
+				foreach (UserDefinedVariableToken var in userDefinedGlobalSaveVarList[i])
+				{
+					//if (!var.IsSavedata) continue;
+					switch (i)
+					{
+						case 0: writer.WriteExtended(var.Name, (string[])var.GetArray()); break;
+						case 1: writer.WriteExtended(var.Name, (Int64[])var.GetArray()); break;
+						case 2: writer.WriteExtended(var.Name, (string[,])var.GetArray()); break;
+						case 3: writer.WriteExtended(var.Name, (Int64[,])var.GetArray()); break;
+						case 4: writer.WriteExtended(var.Name, (string[, ,])var.GetArray()); break;
+						case 5: writer.WriteExtended(var.Name, (Int64[, ,])var.GetArray()); break;
+					}
+				}
+				writer.EmuSeparete();
+			}
+		}
+
+		public void LoadGlobalFromStream1808(EraDataReader reader)
+		{
+			Dictionary<string, List<string>> strListDic = null;
+			Dictionary<string, List<Int64>> intListDic = null;
+			Dictionary<string, List<string[]>> str2DListDic = null;
+			Dictionary<string, List<Int64[]>> int2DListDic = null;
+			Dictionary<string, List<List<string[]>>> str3DListDic = null;
+			Dictionary<string, List<List<Int64[]>>> int3DListDic = null;
+			strListDic = reader.ReadStringArrayExtended();
+			intListDic = reader.ReadInt64ArrayExtended();
+			str2DListDic = reader.ReadStringArray2DExtended();
+			int2DListDic = reader.ReadInt64Array2DExtended();
+			str3DListDic = reader.ReadStringArray3DExtended();
+			int3DListDic = reader.ReadInt64Array3DExtended();
+			List<UserDefinedVariableToken> varList = null;
+
+			int i = 0;
+			varList = userDefinedGlobalSaveVarList[i]; i++;
+			foreach (UserDefinedVariableToken var in varList)
+				if (strListDic.ContainsKey(var.Name))
+					copyListToArray(strListDic[var.Name], (string[])var.GetArray());
+
+			varList = userDefinedGlobalSaveVarList[i]; i++;
+			foreach (UserDefinedVariableToken var in varList)
+				if (intListDic.ContainsKey(var.Name))
+					copyListToArray(intListDic[var.Name], (Int64[])var.GetArray());
+
+			varList = userDefinedGlobalSaveVarList[i]; i++;
+			foreach (UserDefinedVariableToken var in varList)
+				if (str2DListDic.ContainsKey(var.Name))
+					copyListToArray2D(str2DListDic[var.Name], (string[,])var.GetArray());
+
+			varList = userDefinedGlobalSaveVarList[i]; i++;
+			foreach (UserDefinedVariableToken var in varList)
+				if (int2DListDic.ContainsKey(var.Name))
+					copyListToArray2D(int2DListDic[var.Name], (Int64[,])var.GetArray());
+
+			varList = userDefinedGlobalSaveVarList[i]; i++;
+			foreach (UserDefinedVariableToken var in varList)
+				if (str3DListDic.ContainsKey(var.Name))
+					copyListToArray3D(str3DListDic[var.Name], (string[, ,])var.GetArray());
+
+			varList = userDefinedGlobalSaveVarList[i]; i++;
+			foreach (UserDefinedVariableToken var in varList)
+				if (int3DListDic.ContainsKey(var.Name))
+					copyListToArray3D(int3DListDic[var.Name], (Int64[, ,])var.GetArray());
+		}
+
+		public void SaveGlobalToStreamBinary(EraBinaryDataWriter writer)
+		{
+			foreach (KeyValuePair<string, VariableToken> pair in varTokenDic)
+			{
+				VariableToken var = pair.Value;
+				if (var.IsSavedata && !var.IsCharacterData && var.IsGlobal)
+				{
+					writer.WriteWithKey(pair.Key, var.GetArray());
+				}
+			}
+			foreach (UserDefinedVariableToken var in userDefinedGlobalVarList)
+			{
+				if (var.IsSavedata)
+					writer.WriteWithKey(var.Name, var.GetArray());
+			}
+		}
+
+		public void SaveToStreamBinary(EraBinaryDataWriter writer)
+		{
+			foreach (KeyValuePair<string, VariableToken> pair in varTokenDic)
+			{
+				VariableToken var = pair.Value;
+				if (var.IsSavedata && !var.IsCharacterData && !var.IsGlobal)
+				{
+					writer.WriteWithKey(pair.Key, var.GetArray());
+				}
+			}
+			foreach (UserDefinedVariableToken var in userDefinedStaticVarList)
+			{
+				if (var.IsSavedata)
+					writer.WriteWithKey(var.Name, var.GetArray());
+			}
+		}
+
+		public void LoadFromStreamBinary(EraBinaryDataReader bReader)
+		{
+			while (LoadVariableBinary(bReader)) { }
+		}
+
+		/// <summary>
+		/// 1808 キャラクタ型でない変数を一つ読む
+		/// ファイル終端の場合はfalseを返す
+		/// </summary>
+		/// <param name="reader"></param>
+		public bool LoadVariableBinary(EraBinaryDataReader reader)
+		{
+			KeyValuePair<string, EraSaveDataType> nameAndType = reader.ReadVariableCode();
+			VariableToken vToken = null;
+			if (nameAndType.Key != null && !GlobalStatic.IdentifierDictionary.getVarTokenIsForbid(nameAndType.Key))
+				vToken = GlobalStatic.IdentifierDictionary.GetVariableToken(nameAndType.Key, null, false);
+			if (vToken != null && (vToken.IsCharacterData || vToken.IsConst || vToken.IsPrivate || vToken.IsLocal || vToken.IsCalc))
+				vToken = null;
+			switch (nameAndType.Value)
+			{
+				case EraSaveDataType.EOF:
+					return false;
+				case EraSaveDataType.Int:
+					if (vToken == null || !vToken.IsInteger || vToken.Dimension != 0)
+						reader.ReadInt();//該当変数なし、or型不一致なら読み捨てる
+					else
+						vToken.SetValue(reader.ReadInt(), null);
+					break;
+				case EraSaveDataType.Str:
+					if (vToken == null || !vToken.IsString || vToken.Dimension != 0)
+						reader.ReadString();
+					else
+						vToken.SetValue(reader.ReadString(), null);
+					break;
+				case EraSaveDataType.IntArray:
+					if (vToken == null || !vToken.IsInteger || vToken.Dimension != 1)
+						reader.ReadIntArray(null, true);
+					else
+						reader.ReadIntArray((long[])vToken.GetArray(), true);
+					break;
+				case EraSaveDataType.IntArray2D:
+					if (vToken == null || !vToken.IsInteger || vToken.Dimension != 2)
+						reader.ReadIntArray2D(null, true);
+					else
+						reader.ReadIntArray2D((long[,])vToken.GetArray(), true);
+					break;
+				case EraSaveDataType.IntArray3D:
+					if (vToken == null || !vToken.IsInteger || vToken.Dimension != 3)
+						reader.ReadIntArray3D(null, true);
+					else
+						reader.ReadIntArray3D((long[, ,])vToken.GetArray(), true);
+					break;
+				case EraSaveDataType.StrArray:
+					if (vToken == null || !vToken.IsString || vToken.Dimension != 1)
+						reader.ReadStrArray(null, true);
+					else
+						reader.ReadStrArray((string[])vToken.GetArray(), true);
+					break;
+				case EraSaveDataType.StrArray2D:
+					if (vToken == null || !vToken.IsString || vToken.Dimension != 2)
+						reader.ReadStrArray2D(null, true);
+					else
+						reader.ReadStrArray2D((string[,])vToken.GetArray(), true);
+					break;
+				case EraSaveDataType.StrArray3D:
+					if (vToken == null || !vToken.IsString || vToken.Dimension != 3)
+						reader.ReadStrArray3D(null, true);
+					else
+						reader.ReadStrArray3D((string[, ,])vToken.GetArray(), true);
+					break;
+				default:
+					throw new FileEE("データ異常");
+			}
+			return true;
+		}
+		#region IDisposable メンバ
+
+		public void Dispose()
+		{
+			ClearLocalValue();
+			for (int i = 0; i < dataIntegerArray.Length; i++)
+				dataIntegerArray[i] = null;
+			for (int i = 0; i < dataStringArray.Length; i++)
+				dataStringArray[i] = null;
+			for (int i = 0; i < characterList.Count; i++)
+				characterList[i].Dispose();
+			characterList.Clear();
+		}
+
+		#endregion
+
+	}
+}

+ 2442 - 0
NTERA/Game/GameData/Variable/VariableEvaluator.cs

@@ -0,0 +1,2442 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Windows.Forms;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.GameProc.Function;
+using MinorShift.Emuera.Sub;
+using MinorShift._Library;
+using NTERA.Interop;
+using SortOrder = MinorShift.Emuera.GameProc.Function.SortOrder;
+
+//using System.Windows.Forms;
+
+namespace MinorShift.Emuera.GameData.Variable
+{
+	internal sealed class VariableEvaluator : IDisposable
+	{
+		readonly GameBase gamebase;
+		readonly ConstantData constant;
+		readonly VariableData varData;
+		MTRandom rand = new MTRandom();
+
+		public VariableData VariableData => varData;
+		internal ConstantData Constant => constant;
+
+		public VariableEvaluator(GameBase gamebase, ConstantData constant)
+		{
+			this.gamebase = gamebase;
+			this.constant = constant;
+			varData = new VariableData(gamebase, constant);
+			GlobalStatic.VariableData = varData;
+		}
+		#region set/get
+
+		public void Randomize(Int64 seed)
+		{
+			rand = new MTRandom(seed);
+		}
+
+		public void InitRanddata()
+		{
+			rand.SetRand(RANDDATA);
+		}
+
+		public void DumpRanddata()
+		{
+			rand.GetRand(RANDDATA);
+		}
+		public Int64 GetNextRand(Int64 max)
+		{
+			return rand.NextInt64(max);
+		}
+
+		public Int64 getPalamLv(Int64 pl, Int64 maxlv)
+		{
+			for (int i = 0; i < (int)maxlv; i++)
+			{
+				if (pl < varData.DataIntegerArray[(int)(VariableCode.PALAMLV & VariableCode.__LOWERCASE__)][i + 1])
+					return i;
+			}
+			return maxlv;
+		}
+
+		public Int64 getExpLv(Int64 pl, Int64 maxlv)
+		{
+			for (int i = 0; i < (int)maxlv; i++)
+			{
+				if (pl < varData.DataIntegerArray[(int)(VariableCode.EXPLV & VariableCode.__LOWERCASE__)][i + 1])
+					return i;
+			}
+			return maxlv;
+		}
+
+		public void SetValueAll(FixedVariableTerm p, Int64 srcValue, int start, int end)
+		{
+			//呼び出し元で判定済み
+			//if (!p.Identifier.IsInteger)
+			//    throw new CodeEE("整数型でない変数" + p.Identifier.Name + "に整数値を代入しようとしました");
+			//if (p.Identifier.Readonly)
+			//    throw new CodeEE("読み取り専用の変数" + p.Identifier.Name + "に代入しようとしました");
+			if (p.Identifier.IsCalc)
+				return;
+			//一応チェック済み
+			//throw new ExeEE("READONLYでないCALC変数の代入処理が設定されていない");
+
+			if (p.Identifier.IsArray1D)
+			{
+				if (start != 0 || end != p.Identifier.GetLength())
+					p.IsArrayRangeValid(start, end, "VARSET", 3L, 4L);
+				else if (p.Identifier.IsCharacterData)
+					p.Identifier.CheckElement(new[] { p.Index1, p.Index2 });
+			}
+			else if (p.Identifier.IsCharacterData)
+			{
+				p.Identifier.CheckElement(new[] { p.Index1, p.Index2, p.Index3 });
+			}
+			p.Identifier.SetValueAll(srcValue, start, end, (int)p.Index1);
+		}
+
+		public void SetValueAll(FixedVariableTerm p, string srcValue, int start, int end)
+		{
+			//呼び出し元で判定済み
+			//if (!p.Identifier.IsString)
+			//    throw new CodeEE("文字列型でない変数" + p.Identifier.Name + "に文字列型を代入しようとしました");
+			//if (p.Identifier.Readonly)
+			//    throw new CodeEE("読み取り専用の変数" + p.Identifier.Name + "に代入しようとしました");
+			if (p.Identifier.IsCalc)
+			{
+				if (p.Identifier.Code == VariableCode.WINDOW_TITLE)
+				{
+					GlobalStatic.Console.SetWindowTitle(srcValue);
+				}
+
+				//一応チェック済み
+				//throw new ExeEE("READONLYでないCALC変数の代入処理が設定されていない");
+			}
+			else
+			{
+				if (p.Identifier.IsArray1D)
+				{
+					if (start != 0 || end != p.Identifier.GetLength())
+						p.IsArrayRangeValid(start, end, "VARSET", 3L, 4L);
+					else if (p.Identifier.IsCharacterData)
+						p.Identifier.CheckElement(new[] { p.Index1, p.Index2 });
+				}
+				else if (p.Identifier.IsCharacterData)
+				{
+                    p.Identifier.CheckElement(new[] { p.Index1, p.Index2, p.Index3 });
+				}
+				p.Identifier.SetValueAll(srcValue, start, end, (int)p.Index1);
+			}
+		}
+
+		public void SetValueAllEachChara(FixedVariableTerm p, SingleTerm index, Int64 srcValue, int start, int end)
+		{
+			if (!p.Identifier.IsInteger)
+				throw new CodeEE("整数型でない変数" + p.Identifier.Name + "に整数値を代入しようとしました");
+			if (p.Identifier.IsConst)
+				throw new CodeEE("読み取り専用の変数" + p.Identifier.Name + "に代入しようとしました");
+			if (p.Identifier.IsCalc)
+				return;
+			//一応チェック済み
+			//throw new ExeEE("READONLYでないCALC変数の代入処理が設定されていない");
+			if (varData.CharacterList.Count == 0)
+				return;
+
+			CharacterData chara = varData.CharacterList[0];
+			Int64 indexNum = -1;
+
+			if (p.Identifier.IsArray1D)
+			{
+				if (index.GetOperandType() == typeof(Int64))
+					indexNum = index.Int;
+				else
+					indexNum = constant.KeywordToInteger(p.Identifier.Code, index.Str, 1);
+                if (indexNum < 0 || indexNum >= ((long[])(p.Identifier.GetArrayChara(0))).Length)
+					throw new CodeEE("Character array variable " + p.Identifier.Name + " at the second argument (" + indexNum + ") is out of range of the array");
+			}
+
+            for (int i = start; i < end; i++)
+            {
+                p.Identifier.SetValue(srcValue, new[] { i, indexNum });
+            }
+		}
+
+		public void SetValueAllEachChara(FixedVariableTerm p, SingleTerm index, string srcValue, int start, int end)
+		{
+			if (!p.Identifier.IsString)
+				throw new CodeEE("文字列型でない変数" + p.Identifier.Name + "に文字列型を代入しようとしました");
+			if (p.Identifier.IsConst)
+				throw new CodeEE("読み取り専用の変数" + p.Identifier.Name + "に代入しようとしました");
+			if (p.Identifier.IsCalc)
+			{
+				if (p.Identifier.Code == VariableCode.WINDOW_TITLE)
+				{
+					GlobalStatic.Console.SetWindowTitle(srcValue);
+					return;
+				}
+				//一応チェック済み
+				//throw new ExeEE("READONLYでないCALC変数の代入処理が設定されていない");
+				return;
+			}
+			if (varData.CharacterList.Count == 0)
+				return;
+
+			Int64 indexNum = -1;
+
+			if (p.Identifier.IsArray1D)
+			{
+				if (index.GetOperandType() == typeof(Int64))
+					indexNum = index.Int;
+				else
+					indexNum = constant.KeywordToInteger(p.Identifier.Code, index.Str, 1);
+                if (indexNum < 0 || indexNum >= ((string[])(p.Identifier.GetArrayChara(0))).Length)
+					throw new CodeEE("Character array variable " + p.Identifier.Name + " at the second argument (" + indexNum + ") is out of range of the array");
+			}
+
+			for (int i = start; i < end; i++)
+			{
+                p.Identifier.SetValue(srcValue, new[] { i, indexNum });
+            }
+		}
+
+		public Int64 GetArraySum(FixedVariableTerm p, Int64 index1, Int64 index2)
+		{
+			Int64 sum = 0;
+
+            if (p.Identifier.IsCharacterData)
+			{
+                if (p.Identifier.IsArray1D)
+                {
+                    for (int i = (int)index1; i < (int)index2; i++)
+                        sum += p.Identifier.GetIntValue(GlobalStatic.EMediator, new[] { p.Index1, i });
+                }
+                else
+                {
+                    for (int i = (int)index1; i < (int)index2; i++)
+                        sum += p.Identifier.GetIntValue(GlobalStatic.EMediator, new[] { p.Index1, p.Index2, i });
+                }
+			}
+			else
+			{
+				if (p.Identifier.IsArray1D)
+				{
+					for (int i = (int)index1; i < (int)index2; i++)
+						sum += p.Identifier.GetIntValue(GlobalStatic.EMediator, new long[] { i });
+				}
+				else if (p.Identifier.IsArray2D)
+				{
+					for (int i = (int)index1; i < (int)index2; i++)
+                        sum += p.Identifier.GetIntValue(GlobalStatic.EMediator, new[] { p.Index1, i });
+				}
+				else
+				{
+					for (int i = (int)index1; i < (int)index2; i++)
+                        sum += p.Identifier.GetIntValue(GlobalStatic.EMediator, new[] { p.Index1, p.Index2, i });
+				}
+			}
+
+			return sum;
+		}
+
+		public Int64 GetArraySumChara(FixedVariableTerm p, Int64 index1, Int64 index2)
+		{
+			Int64 sum = 0;
+
+            for (int i = (int)index1; i < (int)index2; i++)
+            {
+                sum += p.Identifier.GetIntValue(GlobalStatic.EMediator, new[] { i, p.Index2 });
+            }
+            return sum;
+		}
+
+        public string GetJoinedStr(FixedVariableTerm p, string delimiter, Int64 index1, Int64 index2)
+        {
+            string sum = "";
+
+            if (p.IsString)
+            {
+	            if (p.Identifier.IsArray1D)
+                {
+                    return string.Join(delimiter, (string[])p.Identifier.GetArray(), (int)index1, (int)index2);
+                }
+
+	            if (p.Identifier.IsArray2D)
+	            {
+		            for (int i = (int)index1; i < (int)index2; i++)
+			            sum += p.Identifier.GetStrValue(GlobalStatic.EMediator, new[] { p.Index1, i }) + ((i + 1 < (int)index2) ? delimiter : "");
+	            }
+	            else
+	            {
+		            for (int i = (int)index1; i < (int)index2; i++)
+			            sum += p.Identifier.GetStrValue(GlobalStatic.EMediator, new[] { p.Index1, p.Index2, i }) + ((i + 1 < (int)index2) ? delimiter : "");
+	            }
+            }
+            else
+            {
+                if (p.Identifier.IsArray1D)
+                {
+                    for (int i = (int)index1; i < (int)index2; i++)
+                        sum += (p.Identifier.GetIntValue(GlobalStatic.EMediator, new long[] {  i })) + ((i + 1 < (int)index2) ? delimiter : "");
+                }
+                else if (p.Identifier.IsArray2D)
+                {
+                    for (int i = (int)index1; i < (int)index2; i++)
+                        sum += (p.Identifier.GetIntValue(GlobalStatic.EMediator, new[] { p.Index1, i })) + ((i + 1 < (int)index2) ? delimiter : "");
+                }
+                else
+                {
+                    for (int i = (int)index1; i < (int)index2; i++)
+                        sum += (p.Identifier.GetIntValue(GlobalStatic.EMediator, new[] { p.Index1, p.Index2, i })) + ((i + 1 < (int)index2) ? delimiter : "");
+                }
+            }
+            return sum;
+        }
+
+        public Int64 GetMatch(FixedVariableTerm p, Int64 target, Int64 start, Int64 end)
+		{
+			Int64 ret = 0;
+
+			for (int i = (int)start; i < (int)end; i++)
+                if (p.Identifier.GetIntValue(GlobalStatic.EMediator, p.Identifier.IsCharacterData ? new[] { p.Index1, i } : new long[] { i }) == target)
+					ret++;
+
+			return ret;
+		}
+
+		public Int64 GetMatch(FixedVariableTerm p, string target, Int64 start, Int64 end)
+		{
+            Int64 ret = 0;
+            bool targetIsNullOrEmpty = string.IsNullOrEmpty(target);
+
+			for (int i = (int)start; i < (int)end; i++)
+                if ((p.Identifier.GetStrValue(GlobalStatic.EMediator, p.Identifier.IsCharacterData ? new[] { p.Index1, i } : new long[] { i }) == target) || (targetIsNullOrEmpty && string.IsNullOrEmpty(p.Identifier.GetStrValue(GlobalStatic.EMediator, p.Identifier.IsCharacterData ? new[] { p.Index1, i } : new long[] { i }))))
+					ret++;
+
+			return ret;
+		}
+
+        public Int64 GetMatchChara(FixedVariableTerm p, Int64 target, Int64 start, Int64 end)
+        {
+            Int64 ret = 0;
+
+            for (int i = (int)start; i < (int)end; i++)
+            {
+                if (p.Identifier.GetIntValue(GlobalStatic.EMediator, new[] { i, p.Index2, p.Index3 }) == target)
+                    ret++;
+            }
+
+            return ret;
+        }
+
+		public Int64 GetMatchChara(FixedVariableTerm p, string target, Int64 start, Int64 end)
+		{
+			Int64 ret = 0;
+			bool targetIsNullOrEmpty = string.IsNullOrEmpty(target);
+
+            for (int i = (int)start; i < (int)end; i++)
+            {
+                if ((p.Identifier.GetStrValue(GlobalStatic.EMediator, new[] { i, p.Index2, p.Index3 }) == target) || (targetIsNullOrEmpty && string.IsNullOrEmpty(p.Identifier.GetStrValue(GlobalStatic.EMediator, new[] { i, p.Index2, p.Index3 }))))
+                    ret++;
+            }
+
+			return ret;
+		}
+
+		public Int64 FindElement(FixedVariableTerm p, Int64 target, Int64 start, Int64 end, bool isExact, bool isLast)
+		{
+			Int64[] array;
+
+			//指定値の配列要素の範囲外かのチェックは済んでるので、これだけでよい
+			if (start >= end)
+				return -1;
+
+			if (p.Identifier.IsCharacterData)
+                array = (long[])p.Identifier.GetArrayChara((int)p.Index1);
+			else
+				array = (Int64[])p.Identifier.GetArray();
+
+			if (isLast)
+			{
+				for (int i = (int)end - 1; i >= (int)start; i--)
+				{
+					if (target == array[i])
+						return i;
+				}
+			}
+			else
+			{
+				for (int i = (int)start; i < (int)end; i++)
+				{
+					if (target == array[i])
+						return i;
+				}
+			}
+			return -1;
+		}
+
+		public Int64 FindElement(FixedVariableTerm p, Regex target, Int64 start, Int64 end, bool isExact, bool isLast)
+		{
+			string[] array;
+
+			//指定値の配列要素の範囲外かのチェックは済んでるので、これだけでよい
+			if (start >= end)
+				return -1;
+
+			if (p.Identifier.IsCharacterData)
+                array = (string[])p.Identifier.GetArrayChara((int)p.Index1);
+			else
+				array = (string[])p.Identifier.GetArray();
+
+			if (isLast)
+			{
+				for (int i = (int)end - 1; i >= (int)start; i--)
+				{
+					if (isExact)
+					{
+						//Nullならないものと見なして飛ばす
+						if (array[i] == null)
+							continue;
+						Match match = target.Match(array[i]);
+						//正規表現に引っかかった文字列の長さ=元の文字列の長さなら完全一致
+						if (match.Success && array[i].Length == match.Length)
+							return i;
+					}
+					else
+					{
+						//Nullならないものと見なして飛ばす
+						if (array[i] == null)
+							continue;
+						//部分一致なのでひっかかればOK
+						if (target.IsMatch(array[i]))
+							return i;
+					}
+				}
+			}
+			else
+			{
+				for (int i = (int)start; i < (int)end; i++)
+				{
+					if (isExact)
+					{
+						//Nullならないものと見なして飛ばす
+						if (array[i] == null)
+							continue;
+						//正規表現に引っかかった文字列の長さ=元の文字列の長さなら完全一致
+						Match match = target.Match(array[i]);
+						if (match.Success && array[i].Length == match.Length)
+							return i;
+					}
+					else
+					{
+						//Nullならないものと見なして飛ばす
+						if (array[i] == null)
+							continue;
+						//部分一致なのでひっかかればOK
+						if (target.IsMatch(array[i]))
+							return i;
+					}
+				}
+			}
+			return -1;
+		}
+
+		public Int64 GetMaxArray(FixedVariableTerm p, Int64 start, Int64 end, bool isMax)
+		{
+            Int64 value;
+            Int64 ret = p.Identifier.GetIntValue(GlobalStatic.EMediator, p.Identifier.IsCharacterData ? new[] { p.Index1, start } : new[] { start });
+			for (int i = (int)start + 1; i < (int)end; i++)
+			{
+                value = p.Identifier.GetIntValue(GlobalStatic.EMediator, p.Identifier.IsCharacterData ? new[] { p.Index1, i } : new long[] { i });
+				if (isMax)
+				{
+                    if (value > ret)
+                        ret = value;
+				}
+				else
+				{
+                    if (value < ret)
+                        ret = value;
+				}
+			}
+			return ret;
+		}
+
+        public Int64 GetMaxArrayChara(FixedVariableTerm p, Int64 start, Int64 end, bool isMax)
+        {
+            Int64 ret;
+            Int64 value;
+
+            ret = p.Identifier.GetIntValue(GlobalStatic.EMediator, new[] { start, p.Index2, p.Index3 });
+            for (int i = (int)start + 1; i < (int)end; i++)
+            {
+                value = p.Identifier.GetIntValue(GlobalStatic.EMediator, new[] { i, p.Index2, p.Index3 });
+
+                if (isMax)
+                {
+                    if (value > ret)
+                        ret = value;
+                }
+                else
+                {
+                    if (value < ret)
+                        ret = value;
+                }
+            }
+
+            return ret;
+        }
+
+		public Int64 GetInRangeArray(FixedVariableTerm p, Int64 min, Int64 max, Int64 start, Int64 end)
+		{
+            Int64 value;
+			Int64 ret = 0;
+
+            for (int i = (int)start; i < (int)end; i++)
+            {
+                value = p.Identifier.GetIntValue(GlobalStatic.EMediator, p.Identifier.IsCharacterData ? new[] { p.Index1, i } : new long[] { i });
+                if (value >= min && value < max)
+                    ret++;
+            }
+
+			return ret;
+		}
+
+		public Int64 GetInRangeArrayChara(FixedVariableTerm p, Int64 min, Int64 max, Int64 start, Int64 end)
+		{
+			Int64 ret = 0;
+            Int64 value;
+
+            for (int i = (int)start; i < (int)end; i++)
+            {
+                value = p.Identifier.GetIntValue(GlobalStatic.EMediator, new[] { i, p.Index2, p.Index3 });
+                if (value >= min && value < max)
+                    ret++;
+            }
+
+			return ret;
+		}
+
+		public void ShiftArray(FixedVariableTerm p, int shift, Int64 def, int start, int num)
+		{
+			Int64[] array;
+			if (p.Identifier.IsCharacterData)
+                array = (long[])p.Identifier.GetArrayChara((int)p.Index1);
+			else
+				array = (Int64[])p.Identifier.GetArray();
+
+			if (start >= array.Length)
+				throw new CodeEE("命令ARRAYREMOVEの第4引数(" + start + ")が配列" + p.Identifier.Name + "の範囲を超えています");
+
+			if (num == -1)
+				num = array.Length - start;
+			if ((start + num) > array.Length)
+				num = array.Length - start;
+
+			if (Math.Abs(shift) >= array.Length && start == 0 && num >= array.Length)
+			{
+				for (int i = 0; i < array.Length; i++)
+					array[i] = def;
+				return;
+			}
+
+			int sourceStart = 0;
+			int destStart = start + shift;
+			int length = num - Math.Abs(shift);
+			if (shift < 0)
+			{
+				sourceStart = -shift;
+				destStart = start;
+			}
+			Int64[] temp = new Int64[num];
+			Buffer.BlockCopy(array, start * 8, temp, 0, 8 * num);
+
+			//これを満たすのはshift > 0であることは自明
+			if (sourceStart == 0)
+			{
+				if (length > 0)
+					for (int i = start; i < (start + shift); i++)
+						array[i] = def;
+				else
+				{
+					for (int i = start; i < (start + num); i++)
+						array[i] = def;
+					return;
+				}
+			}
+			else
+			{
+				if (length > 0)
+					for (int i = (start + length); i < (start + num); i++)
+						array[i] = def;
+				else
+				{
+					for (int i = start; i < (start + num); i++)
+						array[i] = def;
+					return;
+				}
+			}
+
+			//if (start > 0)
+			//    //Array.Copy(temp, 0, array, 0, start);
+			//    Buffer.BlockCopy(temp, 0, array, 0, 8 * start);
+
+			if (length > 0)
+				//Array.Copy(temp, sourceStart, array, destStart, length);
+				Buffer.BlockCopy(temp, sourceStart * 8, array, destStart * 8, length * 8);
+
+			//if ((start + num) < array.Length)
+			//    //Array.Copy(temp, (start + num), array, (start + num), array.Length - (start + num));
+			//    Buffer.BlockCopy(temp, (start + num) * 8, array, (start + num) * 8, (array.Length - (start + num)) * 8);
+		}
+
+		public void ShiftArray(FixedVariableTerm p, int shift, string def, int start, int num)
+		{
+			string[] arrays;
+			if (p.Identifier.IsCharacterData)
+                arrays = (string[])p.Identifier.GetArrayChara((int)p.Index1);
+			else
+				arrays = (string[])p.Identifier.GetArray();
+
+			if (start >= arrays.Length)
+				throw new CodeEE("命令ARRAYREMOVEの第4引数(" + start + ")が配列" + p.Identifier.Name + "の範囲を超えています");
+
+			//for (int i = 0; i < arrays.Length; i++)
+			//    arrays[i] = "";
+			//Array.Clear(arrays, 0, arrays.Length);
+
+			if (num == -1)
+				num = arrays.Length - start;
+			if ((start + num) > arrays.Length)
+				num = arrays.Length - start;
+
+			if (Math.Abs(shift) >= arrays.Length && start == 0 && num >= arrays.Length)
+			{
+				for (int i = 0; i < arrays.Length; i++)
+					arrays[i] = def;
+				return;
+			}
+
+			//if (start > 0)
+			//    Array.Copy(temps, 0, arrays, 0, start);
+
+			int sourceStart = 0;
+			int destStart = start + shift;
+			int length = num - Math.Abs(shift);
+			if (shift < 0)
+			{
+				sourceStart = -shift;
+				destStart = start;
+			}
+			string[] temps = new string[num];
+			Array.Copy(arrays, start, temps, 0, num);
+
+			if (destStart > start)
+			{
+				if (length > 0)
+					for (int i = start; i < (start + shift); i++)
+						arrays[i] = def;
+				else
+				{
+					for (int i = start; i < (start + num); i++)
+						arrays[i] = def;
+					return;
+				}
+			}
+			else
+			{
+				if (length > 0)
+					for (int i = (start + length); i < (start + num); i++)
+						arrays[i] = def;
+				else
+				{
+					for (int i = start; i < (start + num); i++)
+						arrays[i] = def;
+					return;
+				}
+			}
+
+			if (length > 0)
+				Array.Copy(temps, sourceStart, arrays, destStart, length);
+			//if ((start + num) < arrays.Length)
+			//    Array.Copy(temps, (start + num), arrays, (start + num), arrays.Length - (start + num));
+		}
+
+		public void RemoveArray(FixedVariableTerm p, int start, int num)
+		{
+			if (p.Identifier.IsInteger)
+			{
+				Int64[] array;
+				if (p.Identifier.IsCharacterData)
+                    array = (long[])p.Identifier.GetArrayChara((int)p.Index1);
+				else
+					array = (Int64[])p.Identifier.GetArray();
+
+                if (start >= array.Length)
+					throw new CodeEE("命令ARRAYREMOVEの第2引数(" + start + ")が配列" + p.Identifier.Name + "の範囲を超えています");
+				if (num <= 0)
+					num = array.Length;
+				Int64[] temp = new Int64[array.Length];
+				//array.CopyTo(temp, 0);
+				//for (int i = 0; i < array.Length; i++)
+				//    array[i] = 0;
+				//Array.Clear(array, 0, array.Length);
+				if (start > 0)
+					//Array.Copy(array, 0, temp, 0, start);
+					Buffer.BlockCopy(array, 0, temp, 0, start * 8);
+				if ((start + num) < array.Length)
+					//Array.Copy(array, (start + num), temp, start, (array.Length - (start + num)));
+					Buffer.BlockCopy(array, (start + num) * 8, temp, start * 8, (array.Length - (start + num)) * 8);
+				//temp.CopyTo(array, 0);
+				Buffer.BlockCopy(temp, 0, array, 0, temp.Length * 8);
+			}
+			else
+			{
+				string[] arrays;
+				if (p.Identifier.IsCharacterData)
+                    arrays = (string[])p.Identifier.GetArrayChara((int)p.Index1);
+				else
+					arrays = (string[])p.Identifier.GetArray();
+
+                if (num <= 0)
+					num = arrays.Length;
+				string[] temps = new string[arrays.Length];
+				//arrays.CopyTo(temps, 0);
+				//for (int i = 0; i < arrays.Length; i++)
+				//    arrays[i] = "";
+				if (start > 0)
+					Array.Copy(arrays, 0, temps, 0, start);
+				if ((start + num) < arrays.Length)
+					Array.Copy(arrays, (start + num), temps, start, (arrays.Length - (start + num)));
+				temps.CopyTo(arrays, 0);
+			}
+		}
+
+		public void SortArray(FixedVariableTerm p, SortOrder order, int start, int num)
+		{
+			if (order == SortOrder.UNDEF)
+				order = SortOrder.ASCENDING;
+			if (p.Identifier.IsInteger)
+			{
+				Int64[] array;
+				if (p.Identifier.IsCharacterData)
+                    array = (long[])p.Identifier.GetArrayChara((int)p.Index1);
+				else
+					array = (Int64[])p.Identifier.GetArray();
+
+                if (start >= array.Length)
+					throw new CodeEE("命令ARRAYSORTの第3引数(" + start + ")が配列" + p.Identifier.Name + "の範囲を超えています");
+				if (num <= 0)
+					num = array.Length - start;
+				Int64[] temp = new Int64[num];
+				Array.Copy(array, start, temp, 0, num);
+
+				if (order == SortOrder.ASCENDING)
+					Array.Sort(temp);
+				else if (order == SortOrder.DESENDING)
+					Array.Sort(temp, delegate(Int64 a, Int64 b) { return b.CompareTo(a); });
+				Array.Copy(temp, 0, array, start, num);
+			}
+			else
+			{
+				string[] array;
+				if (p.Identifier.IsCharacterData)
+                    array = (string[])p.Identifier.GetArrayChara((int)p.Index1);
+                else
+					array = (string[])p.Identifier.GetArray();
+
+                if (start >= array.Length)
+					throw new CodeEE("命令ARRAYSORTの第3引数(" + start + ")が配列" + p.Identifier.Name + "の範囲を超えています");
+				if (num <= 0)
+					num = array.Length - start;
+				string[] temp = new string[num];
+				Array.Copy(array, start, temp, 0, num);
+
+				if (order == SortOrder.ASCENDING)
+					Array.Sort(temp);
+				else if (order == SortOrder.DESENDING)
+					Array.Sort(temp, delegate(string a, string b) { return b.CompareTo(a); });
+				Array.Copy(temp, 0, array, start, num);
+			}
+		}
+
+
+
+		public void CopyArray(VariableToken var1, VariableToken var2)
+		{
+			if (var1.IsInteger)
+			{
+				if (var1.IsArray1D)
+				{
+					Int64[] array1 = (Int64[])var1.GetArray();
+					Int64[] array2 = (Int64[])var2.GetArray();
+					int length = (array1.Length >= array2.Length) ? array2.Length : array1.Length;
+					for (int i = 0; i < length; i++)
+						array2[i] = array1[i];
+				}
+				else if (var1.IsArray2D)
+				{
+					Int64[,] array1 = (Int64[,])var1.GetArray();
+					Int64[,] array2 = (Int64[,])var2.GetArray();
+					int length1 = (array1.GetLength(0) >= array2.GetLength(0)) ? array2.GetLength(0) : array1.GetLength(0);
+					int length2 = (array1.GetLength(1) >= array2.GetLength(1)) ? array2.GetLength(1) : array1.GetLength(1);
+					for (int i = 0; i < length1; i++)
+					{
+						for (int j = 0; j < length2; j++)
+							array2[i, j] = array1[i, j];
+					}
+				}
+				else
+				{
+					Int64[, ,] array1 = (Int64[, ,])var1.GetArray();
+					Int64[, ,] array2 = (Int64[, ,])var2.GetArray();
+					int length1 = (array1.GetLength(0) >= array2.GetLength(0)) ? array2.GetLength(0) : array1.GetLength(0);
+					int length2 = (array1.GetLength(1) >= array2.GetLength(1)) ? array2.GetLength(1) : array1.GetLength(1);
+					int length3 = (array1.GetLength(2) >= array2.GetLength(2)) ? array2.GetLength(2) : array1.GetLength(2);
+					for (int i = 0; i < length1; i++)
+					{
+						for (int j = 0; j < length2; j++)
+						{
+							for (int k = 0; k < length3; k++)
+								array2[i, j, k] = array1[i, j, k];
+						}
+					}
+				}
+			}
+			else
+			{
+				if (var1.IsArray1D)
+				{
+					string[] array1 = (string[])var1.GetArray();
+					string[] array2 = (string[])var2.GetArray();
+					int length = (array1.Length >= array2.Length) ? array2.Length : array1.Length;
+					for (int i = 0; i < length; i++)
+						array2[i] = array1[i];
+				}
+				else if (var1.IsArray2D)
+				{
+					string[,] array1 = (string[,])var1.GetArray();
+					string[,] array2 = (string[,])var2.GetArray();
+					int length1 = (array1.GetLength(0) >= array2.GetLength(0)) ? array2.GetLength(0) : array1.GetLength(0);
+					int length2 = (array1.GetLength(1) >= array2.GetLength(1)) ? array2.GetLength(1) : array1.GetLength(1);
+					for (int i = 0; i < length1; i++)
+					{
+						for (int j = 0; j < length2; j++)
+							array2[i, j] = array1[i, j];
+					}
+				}
+				else
+				{
+					string[, ,] array1 = (string[, ,])var1.GetArray();
+					string[, ,] array2 = (string[, ,])var2.GetArray();
+					int length1 = (array1.GetLength(0) >= array2.GetLength(0)) ? array2.GetLength(0) : array1.GetLength(0);
+					int length2 = (array1.GetLength(1) >= array2.GetLength(1)) ? array2.GetLength(1) : array1.GetLength(1);
+					int length3 = (array1.GetLength(2) >= array2.GetLength(2)) ? array2.GetLength(2) : array1.GetLength(2);
+					for (int i = 0; i < length1; i++)
+					{
+						for (int j = 0; j < length2; j++)
+						{
+							for (int k = 0; k < length3; k++)
+								array2[i, j, k] = array1[i, j, k];
+						}
+					}
+				}
+			}
+		}
+
+
+		public string GetHavingItemsString()
+		{
+			Int64[] array = ITEM;
+			string[] itemnames = ITEMNAME;
+			int length = Math.Min(array.Length, itemnames.Length);
+			int count = 0;
+			StringBuilder builder = new StringBuilder(100);
+			builder.Append("Owned Items: ");
+			for (int i = 0; i < length; i++)
+			{
+				if (array[i] == 0)
+					continue;
+				count++;
+                if (itemnames[i] != null)
+                    builder.Append(Translation.translate(itemnames[i], "Item", true));//Bartoum: This is for PRINT_ITEM
+				builder.Append("(");
+				builder.Append(array[i].ToString());
+				builder.Append(")  ");
+			}
+			if (count == 0)
+				builder.Append("None");
+			return builder.ToString();
+		}
+
+		//public string GetItemSalesString()
+		//{
+		//	Int64[] itemsales = varData.DataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.ITEMSALES];
+		//	string[] itemname = constant.GetCsvNameList(VariableCode.ITEMNAME);
+		//	StringBuilder builder = new StringBuilder(100);
+		//	for (int i = 0; i < itemsales.Length; i++)
+		//	{
+		//		if (itemsales[i] != 0)
+		//			continue;
+		//		builder.Append(itemname[i]);
+		//		builder.Append("(");
+		//		builder.Append(itemsales[i].ToString());
+		//		builder.Append(")");
+		//	}
+		//	return builder.ToString();
+		//}
+
+		public string GetCharacterDataString(Int64 target, FunctionCode func)
+		{
+			StringBuilder builder = new StringBuilder(100);
+			if ((target < 0) || (target >= varData.CharacterList.Count))
+				throw new CodeEE("Attempted to reference a registered character that does not exist");
+			CharacterData chara = varData.CharacterList[(int)target];
+			Int64[] array = null;
+			string[] arrayName = null;
+			int i = 0;
+			switch (func)
+			{
+				case FunctionCode.PRINT_ABL:
+					array = chara.DataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.ABL];
+					arrayName = constant.GetCsvNameList(VariableCode.ABLNAME);
+					for (i = 0; i < array.Length; i++)
+					{
+						if (i >= arrayName.Length)
+							break;
+						if (array[i] == 0)
+							continue;
+						if (string.IsNullOrEmpty(arrayName[i]))
+							continue;
+						builder.Append(arrayName[i]);
+						builder.Append("LV");
+						builder.Append(array[i].ToString());
+						builder.Append(" ");
+
+					}
+					break;
+				case FunctionCode.PRINT_TALENT:
+					array = chara.DataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.TALENT];
+					arrayName = constant.GetCsvNameList(VariableCode.TALENTNAME);
+					for (i = 0; i < array.Length; i++)
+					{
+						if (i >= arrayName.Length)
+							break;
+						if (array[i] == 0)
+							continue;
+						if (string.IsNullOrEmpty(arrayName[i]))
+							continue;
+						builder.Append("[");
+						builder.Append(arrayName[i]);
+						builder.Append("]");
+					}
+					break;
+				case FunctionCode.PRINT_MARK:
+					array = chara.DataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.MARK];
+					arrayName = constant.GetCsvNameList(VariableCode.MARKNAME);
+					for (i = 0; i < array.Length; i++)
+					{
+						if (i >= arrayName.Length)
+							break;
+						if (array[i] == 0)
+							continue;
+						if (string.IsNullOrEmpty(arrayName[i]))
+							continue;
+						builder.Append(arrayName[i]);
+						builder.Append("LV");
+						builder.Append(array[i].ToString());
+						builder.Append(" ");
+					}
+					break;
+				case FunctionCode.PRINT_EXP:
+					array = chara.DataIntegerArray[(int)VariableCode.__LOWERCASE__ & (int)VariableCode.EXP];
+					arrayName = constant.GetCsvNameList(VariableCode.EXPNAME);
+					for (i = 0; i < array.Length; i++)
+					{
+						if (i >= arrayName.Length)
+							break;
+						if (array[i] == 0)
+							continue;
+						if (string.IsNullOrEmpty(arrayName[i]))
+							continue;
+						builder.Append(arrayName[i]);
+						builder.Append(array[i].ToString());
+						builder.Append(" ");
+					}
+					break;
+				//現状ここに来ることはないはず
+				//default:
+				//    throw new ExeEE("未定義の関数");
+			}
+			return builder.ToString();
+		}
+
+		public string GetCharacterParamString(Int64 target, int paramCode)
+		{
+			if ((target < 0) || (target >= varData.CharacterList.Count))
+				throw new CodeEE("Attempted to reference a registered character that does not exist");
+			//そもそも呼び出し元がint i = 0; i < 100; i++)でこの条件が満たされる可能性0
+			//if ((paramCode < 0) || (paramCode >= constant.ParamName.Length))
+			//    throw new ExeEE("存在しない名称を取得しようとした");
+			CharacterData chara = varData.CharacterList[(int)target];
+			Int64 param = chara.DataIntegerArray[(int)(VariableCode.PALAM & VariableCode.__LOWERCASE__)][paramCode];
+			Int64[] paramlv = varData.DataIntegerArray[(int)(VariableCode.PALAMLV & VariableCode.__LOWERCASE__)];
+			string paramName = constant.GetCsvNameList(VariableCode.PALAMNAME)[paramCode];
+            paramName = Translation.translate(paramName, "Palam", true);//Bartoum: this is for PRINT_PALAM
+			if ((param == 0) && (string.IsNullOrEmpty(paramName)))
+				return null;
+			if (paramName == null)
+				paramName = "";
+			char c = '-';
+			Int64 border = paramlv[1];
+			if (param >= border)
+			{
+				c = '=';
+				border = paramlv[2];
+			}
+			if (param >= border)
+			{
+				c = '>';
+				border = paramlv[3];
+			}
+			if (param >= border)
+			{
+				c = '*';
+				border = paramlv[4];
+			}
+			StringBuilder bar = new StringBuilder(100);
+
+			bar.Append('[');
+			if ((border <= 0) || (border <= param))
+				bar.Append(c, 10);
+			else if (param <= 0)
+				bar.Append('.', 10);
+			else
+			{
+				unchecked
+				{
+					int count = (int)(param * 10 / border);
+					bar.Append(c, count);
+					bar.Append('.', 10 - count);
+				}
+			}
+			bar.Append(']');
+			return string.Format("{0}{1}{2,6}", paramName, bar, param);
+
+		}
+
+		public void AddCharacter(Int64 charaTmplNo)
+		{
+			CharacterTemplate tmpl = constant.GetCharacterTemplate(charaTmplNo);
+			if (tmpl == null)
+				throw new CodeEE("Attempted to create an undefined character");
+			CharacterData chara = new CharacterData(constant, tmpl, varData);
+			varData.CharacterList.Add(chara);
+		}
+
+		public void AddCharacter_UseSp(Int64 charaTmplNo, bool isSp)
+		{
+			CharacterTemplate tmpl = constant.GetCharacterTemplate_UseSp(charaTmplNo, isSp);
+			if (tmpl == null)
+				throw new CodeEE("Attempted to create an undefined character");
+			CharacterData chara = new CharacterData(constant, tmpl, varData);
+			varData.CharacterList.Add(chara);
+		}
+
+		public void AddCharacterFromCsvNo(Int64 CsvNo)
+		{
+			CharacterTemplate tmpl = constant.GetCharacterTemplateFromCsvNo(CsvNo);
+			if (tmpl == null)
+				//throw new CodeEE("Attempted to create an undefined character");
+				tmpl = constant.GetPseudoChara();
+			CharacterData chara = new CharacterData(constant, tmpl, varData);
+			varData.CharacterList.Add(chara);
+		}
+
+		public void AddPseudoCharacter()
+		{
+			CharacterTemplate tmpl = constant.GetPseudoChara();
+			CharacterData chara = new CharacterData(constant, tmpl, varData);
+			varData.CharacterList.Add(chara);
+		}
+
+		public void DelCharacter(Int64 charaNo)
+		{
+			if ((charaNo < 0) || (charaNo >= varData.CharacterList.Count))
+				throw new CodeEE("Attempted to delete registered characters (" + charaNo + ") that do not exist");
+			varData.CharacterList[(int)charaNo].Dispose();
+			varData.CharacterList.RemoveAt((int)charaNo);
+		}
+
+		public void DelCharacter(Int64[] charaNoList)
+		{
+			List<CharacterData> DelList = new List<CharacterData>();
+			foreach(Int64 charaNo in charaNoList)
+			{
+				if ((charaNo < 0) || (charaNo >= varData.CharacterList.Count))
+					throw new CodeEE("Attempted to delete registered characters (" + charaNoList + ") that do not exist");
+				CharacterData chara = varData.CharacterList[(int)charaNo];
+				if (DelList.Contains(chara))
+					throw new CodeEE("Identical registered character number (" + charaNo + ") has been specified more than once");
+				DelList.Add(chara);
+				chara.Dispose();
+			}
+			foreach (CharacterData chara in DelList)
+				varData.CharacterList.Remove(chara);
+		}
+
+		public void DelAllCharacter()
+		{
+			if (varData.CharacterList.Count == 0)
+				return;
+			foreach (CharacterData chara in varData.CharacterList)
+				chara.Dispose();
+			varData.CharacterList.Clear();
+		}
+
+		public void PickUpChara(Int64[] NoList)
+		{
+			List<Int64> pickList = new List<long>();
+			Int64 oldTarget = TARGET;
+			Int64 oldAssi = ASSI;
+			Int64 oldMaster = MASTER;
+			TARGET = -1;
+			ASSI = -1;
+			MASTER = -1;
+			//同じキャラが複数出てこないようにリストを整理
+			for (int i = 0; i < NoList.Length; i++)
+			{
+				if (!pickList.Contains(NoList[i]) && NoList[i] >= 0)
+					pickList.Add(NoList[i]);
+			}
+			for (int i = 0; i < pickList.Count; i++)
+			{
+				if (i != pickList[i])
+				{
+					SwapChara(pickList[i], i);
+					if (pickList.IndexOf(i) > i)
+						pickList[pickList.IndexOf(i)] = pickList[i];
+				}
+				if (TARGET < 0 && pickList[i] == oldTarget)
+					TARGET = i;
+				if (ASSI < 0 && pickList[i] == oldAssi)
+					ASSI = i;
+				if (MASTER < 0 && pickList[i] == oldMaster)
+					MASTER = i;
+			}
+			if (pickList.Count < varData.CharacterList.Count)
+			{
+				for (int i = (varData.CharacterList.Count - 1); i >= pickList.Count; i--)
+					DelCharacter(i);
+			}
+		}
+
+		public void ResetData()
+		{
+			//グローバルは初期化しない方が都合がよい。
+			//varData.SetDefaultGlobalValue();
+			varData.SetDefaultLocalValue();
+			varData.SetDefaultValue(constant);
+			foreach (CharacterData chara in varData.CharacterList)
+				chara.Dispose();
+			varData.CharacterList.Clear();
+		}
+
+		public void ResetGlobalData()
+		{
+			varData.SetDefaultGlobalValue();
+		}
+
+		public void CopyChara(Int64 x, Int64 y)
+		{
+			if ((x < 0) || (x >= varData.CharacterList.Count))
+				throw new CodeEE("Source of a copy character does not exist");
+			if ((y < 0) || (y >= varData.CharacterList.Count))
+				throw new CodeEE("Destination of a copy character does not exist");
+			varData.CharacterList[(int)x].CopyTo(varData.CharacterList[(int)y], varData);
+		}
+
+		public void AddCopyChara(Int64 x)
+		{
+			if ((x < 0) || (x >= varData.CharacterList.Count))
+				throw new CodeEE("Source of a copy character does not exist");
+			AddPseudoCharacter();
+			varData.CharacterList[(int)x].CopyTo(varData.CharacterList[varData.CharacterList.Count - 1], varData);
+		}
+
+		public void SwapChara(Int64 x, Int64 y)
+		{
+			if (((x < 0) || (x >= varData.CharacterList.Count)) || ((y < 0) || (y >= varData.CharacterList.Count)))
+				throw new CodeEE("Attempted to replace a registered character that does not exist");
+			if (x == y)
+				return;
+			CharacterData data = varData.CharacterList[(int)y];
+			varData.CharacterList[(int)y] = varData.CharacterList[(int)x];
+			varData.CharacterList[(int)x] = data;
+		}
+
+		public void SortChara(VariableToken sortkey, Int64 elem, SortOrder sortorder, bool fixMaster)
+		{
+			if (varData.CharacterList.Count <= 1)
+				return;
+			if (sortorder == SortOrder.UNDEF)
+				sortorder = SortOrder.ASCENDING;
+			if (sortkey == null)
+				sortkey = GlobalStatic.VariableData.GetSystemVariableToken("NO");
+			CharacterData masterChara = null;
+			CharacterData targetChara = null;
+			CharacterData assiChara = null;
+			if (MASTER >= 0 && MASTER < varData.CharacterList.Count)
+				masterChara = varData.CharacterList[(int)MASTER];
+			if (TARGET >= 0 && TARGET < varData.CharacterList.Count)
+				targetChara = varData.CharacterList[(int)TARGET];
+			if (ASSI >= 0 && ASSI < varData.CharacterList.Count)
+				assiChara = varData.CharacterList[(int)ASSI];
+
+			for (int i = 0; i < varData.CharacterList.Count; i++)
+			{
+				varData.CharacterList[i].temp_CurrentOrder = i;
+				varData.CharacterList[i].SetSortKey(sortkey, elem);
+			}
+			if ((fixMaster) && (masterChara != null))
+			{
+				if (varData.CharacterList.Count <= 2)
+					return;
+				varData.CharacterList.Remove(masterChara);
+			}
+			if (sortorder == SortOrder.ASCENDING)
+				varData.CharacterList.Sort(CharacterData.AscCharacterComparison);
+			else// if (sortorder == SortOrder.DESENDING)
+				varData.CharacterList.Sort(CharacterData.DescCharacterComparison);
+			//引数解析でチェック済み
+			//else
+			//    throw new ExeEE("ソート順序不明");
+
+			if ((fixMaster) && (masterChara != null))
+			{
+				varData.CharacterList.Insert((int)MASTER, masterChara);
+			}
+			for (int i = 0; i < varData.CharacterList.Count; i++)
+				varData.CharacterList[i].temp_CurrentOrder = i;
+			if ((masterChara != null) && (!fixMaster))
+				MASTER = masterChara.temp_CurrentOrder;
+			if (targetChara != null)
+				TARGET = targetChara.temp_CurrentOrder;
+			if (assiChara != null)
+				ASSI = assiChara.temp_CurrentOrder;
+		}
+
+
+		internal Int64 FindChara(VariableToken varID, Int64 elem64, string word, Int64 startIndex, Int64 lastIndex, bool isLast)
+		{
+			if (startIndex >= lastIndex)
+				return -1;
+			FixedVariableTerm fvp = new FixedVariableTerm(varID);
+			if (varID.IsArray1D)
+				fvp.Index2 = elem64;
+			else if (varID.IsArray2D)
+			{
+				fvp.Index2 = elem64 >> 32;
+				fvp.Index3 = elem64 & 0x7FFFFFFF;
+			}
+			int count = varData.CharacterList.Count;
+			if (isLast)
+			{
+				for (Int64 i = lastIndex - 1; i >= startIndex; i--)
+				{
+					fvp.Index1 = i;
+					if (word == fvp.GetStrValue(null))
+						return i;
+				}
+			}
+			else
+			{
+				for (Int64 i = startIndex; i < lastIndex; i++)
+				{
+					fvp.Index1 = i;
+					if (word == fvp.GetStrValue(null))
+						return i;
+				}
+			}
+			return -1;
+		}
+
+		internal Int64 FindChara(VariableToken varID, Int64 elem64, Int64 word, Int64 startIndex, Int64 lastIndex, bool isLast)
+		{
+			if (startIndex >= lastIndex)
+				return -1;
+			FixedVariableTerm fvp = new FixedVariableTerm(varID);
+			if (varID.IsArray1D)
+				fvp.Index2 = elem64;
+			else if (varID.IsArray2D)
+			{
+				fvp.Index2 = elem64 >> 32;
+				fvp.Index3 = elem64 & 0x7FFFFFFF;
+			}
+			int count = varData.CharacterList.Count;
+			if (isLast)
+			{
+				for (Int64 i = lastIndex - 1; i >= startIndex; i--)
+				{
+					fvp.Index1 = i;
+					if (word == fvp.GetIntValue(null))
+						return i;
+				}
+			}
+			else
+			{
+				for (Int64 i = startIndex; i < lastIndex; i++)
+				{
+					fvp.Index1 = i;
+					if (word == fvp.GetIntValue(null))
+						return i;
+				}
+			}
+			return -1;
+		}
+
+		public Int64 GetChara(Int64 charaNo)
+		{
+			int i;
+			for (i = 0; i < varData.CharacterList.Count; i++)
+			{
+				if (varData.CharacterList[i].NO == charaNo)
+					return i;
+			}
+			return -1;
+		}
+
+		public Int64 GetChara_UseSp(Int64 charaNo, bool getSp)
+		{
+			//後天的にNOを変更する場合も考慮し、chara*.csvで定義されているかどうかは調べない。
+			//CharacterTemplate tmpl = constant.GetCharacterTemplate(charaNo, false);
+			//if (tmpl == null)
+			//    return -1;
+			int i;
+			for (i = 0; i < varData.CharacterList.Count; i++)
+			{
+				if (varData.CharacterList[i].NO == charaNo)
+				{
+					bool isSp = varData.CharacterList[i].CFlag[0] != 0;
+					if (isSp == getSp)
+						return i;
+				}
+			}
+			return -1;
+		}
+
+		public Int64 ExistCsv(Int64 charaNo, bool getSp)
+		{
+			//SPキャラ廃止に伴う問題は呼び出し元で処理
+			CharacterTemplate tmpl = constant.GetCharacterTemplate_UseSp(charaNo, getSp);
+			if (tmpl == null)
+				return 0;
+			return 1;
+		}
+
+		public string GetCharacterStrfromCSVData(Int64 charaTmplNo, CharacterStrData type, bool isSp, Int64 arg2Long)
+		{
+			//SPキャラ廃止に伴う問題は呼び出し元で処理
+			CharacterTemplate tmpl = constant.GetCharacterTemplate_UseSp(charaTmplNo, isSp);
+			if (tmpl == null)
+				throw new CodeEE("Attempted to refer to an undefined character");
+			int arg2 = (int)arg2Long;
+			switch (type)
+			{
+				case CharacterStrData.CALLNAME:
+					if (tmpl.Callname != null)
+						return tmpl.Callname;
+					else
+						return "";
+				case CharacterStrData.NAME:
+					if (tmpl.Name != null)
+						return tmpl.Name;
+					else
+						return "";
+				case CharacterStrData.NICKNAME:
+					if (tmpl.Nickname != null)
+						return tmpl.Nickname;
+					else
+						return "";
+				case CharacterStrData.MASTERNAME:
+					if (tmpl.Mastername != null)
+						return tmpl.Mastername;
+					else
+						return "";
+				case CharacterStrData.CSTR:
+                    if (tmpl.CStr != null)
+                    {
+                        string ret = null;
+                        if (arg2 >= tmpl.ArrayStrLength(CharacterStrData.CSTR) || arg2 < 0)
+                            throw new CodeEE("Attempted reference is out of the CSTR reference range");
+                        if (tmpl.CStr.TryGetValue(arg2, out ret))
+							return ret;
+
+	                    return "";
+                    }
+					else
+						return "";
+				default:
+					throw new CodeEE("Attempted to reference data that does not exist");
+			}
+		}
+
+		public Int64 GetCharacterIntfromCSVData(Int64 charaTmplNo, CharacterIntData type, bool isSp, Int64 arg2Long)
+		{
+			//SPキャラ廃止に伴う問題は呼び出し元で処理
+			CharacterTemplate tmpl = constant.GetCharacterTemplate_UseSp(charaTmplNo, isSp);
+			if (tmpl == null)
+				throw new CodeEE("Attempted to refer to an undefined character");
+			if (arg2Long >= tmpl.ArrayLength(type) || arg2Long < 0)
+				throw new CodeEE("Attempted reference is out of the reference range");
+			int arg2 = (int)arg2Long;
+			Dictionary<int, Int64> intDic = null;
+			switch (type)
+			{
+				case CharacterIntData.BASE:
+					intDic = tmpl.Maxbase; break;
+				case CharacterIntData.MARK:
+					intDic = tmpl.Mark; break;
+				case CharacterIntData.ABL:
+					intDic = tmpl.Abl; break;
+				case CharacterIntData.EXP:
+					intDic = tmpl.Exp; break;
+				case CharacterIntData.RELATION:
+					intDic = tmpl.Relation; break;
+				case CharacterIntData.TALENT:
+					intDic = tmpl.Talent; break;
+				case CharacterIntData.CFLAG:
+					intDic = tmpl.CFlag; break;
+				case CharacterIntData.EQUIP:
+					intDic = tmpl.Equip; break;
+				case CharacterIntData.JUEL:
+					intDic = tmpl.Juel; break;
+				default:
+					throw new CodeEE("Attempted to reference data that does not exist");
+			}
+			Int64 ret;
+			if (intDic.TryGetValue(arg2, out ret))
+				return ret;
+			return 0L;
+		}
+
+		public void UpdateInBeginTrain()
+		{
+			ASSIPLAY = 0;
+			PREVCOM = -1;
+			NEXTCOM = -1;
+			Int64[] array;
+			string[] sarray;
+			array = varData.DataIntegerArray[(int)(VariableCode.TFLAG & VariableCode.__LOWERCASE__)];
+			for (int i = 0; i < array.Length; i++)
+				array[i] = 0;
+			sarray = varData.DataStringArray[(int)(VariableCode.TSTR & VariableCode.__LOWERCASE__)];
+			for (int i = 0; i < sarray.Length; i++)
+				sarray[i] = "";
+			//本家の仕様にあわせ、選択中以外のキャラクタも全部リセット。
+			foreach (CharacterData chara in varData.CharacterList)
+			{
+				array = chara.DataIntegerArray[(int)(VariableCode.GOTJUEL & VariableCode.__LOWERCASE__)];
+				for (int i = 0; i < array.Length; i++)
+					array[i] = 0;
+				array = chara.DataIntegerArray[(int)(VariableCode.TEQUIP & VariableCode.__LOWERCASE__)];
+				for (int i = 0; i < array.Length; i++)
+					array[i] = 0;
+				array = chara.DataIntegerArray[(int)(VariableCode.EX & VariableCode.__LOWERCASE__)];
+				for (int i = 0; i < array.Length; i++)
+					array[i] = 0;
+				//STAINは関数に切り出す(RESET_STAIN対応のため)
+				setDefaultStain(chara);
+				array = chara.DataIntegerArray[(int)(VariableCode.PALAM & VariableCode.__LOWERCASE__)];
+				for (int i = 0; i < array.Length; i++)
+					array[i] = 0;
+				//1.728 このタイミングでSOURCEも更新されていた
+				array = chara.DataIntegerArray[(int)(VariableCode.SOURCE & VariableCode.__LOWERCASE__)];
+				for (int i = 0; i < array.Length; i++)
+					array[i] = 0;
+				//1.728 NOWEXはここでは更新されていない
+				//1736f CTFLAGはTFLAGと同じ仕様で
+				array = chara.DataIntegerArray[(int)(VariableCode.TCVAR & VariableCode.__LOWERCASE__)];
+				for (int i = 0; i < array.Length; i++)
+					array[i] = 0;
+			}
+		}
+
+		public void UpdateAfterShowUsercom()
+		{
+			//UP = 0,DOWN = 0,LOSEBASE = 0
+			Int64[] array;
+			array = varData.DataIntegerArray[(int)(VariableCode.UP & VariableCode.__LOWERCASE__)];
+			for (int i = 0; i < array.Length; i++)
+				array[i] = 0;
+			array = varData.DataIntegerArray[(int)(VariableCode.DOWN & VariableCode.__LOWERCASE__)];
+			for (int i = 0; i < array.Length; i++)
+				array[i] = 0;
+			array = varData.DataIntegerArray[(int)(VariableCode.LOSEBASE & VariableCode.__LOWERCASE__)];
+			for (int i = 0; i < array.Length; i++)
+				array[i] = 0;
+			foreach (CharacterData chara in varData.CharacterList)
+			{
+				array = chara.DataIntegerArray[(int)(VariableCode.DOWNBASE & VariableCode.__LOWERCASE__)];
+				for (int i = 0; i < array.Length; i++)
+					array[i] = 0;
+				array = chara.DataIntegerArray[(int)(VariableCode.CUP & VariableCode.__LOWERCASE__)];
+				for (int i = 0; i < array.Length; i++)
+					array[i] = 0;
+				array = chara.DataIntegerArray[(int)(VariableCode.CDOWN & VariableCode.__LOWERCASE__)];
+				for (int i = 0; i < array.Length; i++)
+					array[i] = 0;
+			}
+
+			//SOURCEはリセットタイミングが違うので消し
+			//1.728 NOWEXも微妙に違うので移動
+		}
+
+		//1.728 NOWEXもリセットタイミングが違うので移動
+		//UP,DOWN,LOSEBASEはUSERCOMに移動する場合にもリセットされるがNOWEXはCOMが実行される場合のみ更新される
+		//なのでEVENTCOM直前に呼ぶ
+		public void UpdateAfterInputCom()
+		{
+			//本家の仕様にあわせ、選択中以外のキャラクタも全部リセット。
+			Int64[] array;
+			foreach (CharacterData chara in varData.CharacterList)
+			{
+				array = chara.DataIntegerArray[(int)(VariableCode.NOWEX & VariableCode.__LOWERCASE__)];
+				for (int i = 0; i < array.Length; i++)
+					array[i] = 0;
+			}
+		}
+
+		//SOURCEのリセットタイミングはUP、DOWN、LOSEBASE、NOWEXと違いSOURCECHECK終了後なので切り分け
+		public void UpdateAfterSourceCheck()
+		{
+			//本家の仕様にあわせ、選択中以外のキャラクタも全部リセット。
+			Int64[] array;
+			foreach (CharacterData chara in varData.CharacterList)
+			{
+				array = chara.DataIntegerArray[(int)(VariableCode.SOURCE & VariableCode.__LOWERCASE__)];
+				for (int i = 0; i < array.Length; i++)
+					array[i] = 0;
+			}
+		}
+
+		//PREVCOMは更新されない。スクリプトの方で更新する必要がある。
+		//Data側からEmueraConsoleを操作するのはここだけ。
+		//1756 ↑だったのは今は昔の話である
+		public void UpdateInUpcheck(IConsole window, bool skipPrint)
+		{
+			Int64[] up, down, param;
+			string[] paramname = constant.GetCsvNameList(VariableCode.PALAMNAME);
+			up = varData.DataIntegerArray[(int)(VariableCode.UP & VariableCode.__LOWERCASE__)];
+			down = varData.DataIntegerArray[(int)(VariableCode.DOWN & VariableCode.__LOWERCASE__)];
+			Int64 target = TARGET;
+			if ((target < 0) || (target >= varData.CharacterList.Count))
+				goto end;
+			CharacterData chara = varData.CharacterList[(int)target];
+			param = chara.DataIntegerArray[(int)(VariableCode.PALAM & VariableCode.__LOWERCASE__)];
+			int length = param.Length;
+			if (param.Length > up.Length)
+				length = up.Length;
+			if (param.Length > down.Length)
+				length = down.Length;
+
+			for (int i = 0; i < length; i++)
+			{
+				//本家の仕様では負の値は無効。
+				if ((up[i] <= 0) && (down[i] <= 0))
+					continue;
+				StringBuilder builder = new StringBuilder();
+				if (!skipPrint)
+				{
+					builder.Append(paramname[i]);
+					builder.Append(' ');
+					builder.Append(param[i].ToString());
+					if (up[i] > 0)
+					{
+						builder.Append('+');
+						builder.Append(up[i].ToString());
+					}
+					if (down[i] > 0)
+					{
+						builder.Append('-');
+						builder.Append(down[i].ToString());
+					}
+				}
+				unchecked { param[i] += up[i] - down[i]; }
+				if (!skipPrint)
+				{
+					builder.Append('=');
+					builder.Append(param[i].ToString());
+					window.Print(builder.ToString());
+					window.NewLine();
+				}
+
+			}
+		end:
+			for (int i = 0; i < up.Length; i++)
+				up[i] = 0;
+			for (int i = 0; i < down.Length; i++)
+				down[i] = 0;
+		}
+
+		public void CUpdateInUpcheck(IConsole window, Int64 target, bool skipPrint)
+		{
+			Int64[] up, down, param;
+			string[] paramname = constant.GetCsvNameList(VariableCode.PALAMNAME);
+			if ((target < 0) || (target >= varData.CharacterList.Count))
+				return;
+			CharacterData chara = varData.CharacterList[(int)target];
+			up = chara.DataIntegerArray[(int)(VariableCode.CUP & VariableCode.__LOWERCASE__)];
+			down = chara.DataIntegerArray[(int)(VariableCode.CDOWN & VariableCode.__LOWERCASE__)];
+			param = chara.DataIntegerArray[(int)(VariableCode.PALAM & VariableCode.__LOWERCASE__)];
+			int length = param.Length;
+			if (param.Length > up.Length)
+				length = up.Length;
+			if (param.Length > down.Length)
+				length = down.Length;
+
+			for (int i = 0; i < length; i++)
+			{
+				//本家の仕様では負の値は無効。
+				if ((up[i] <= 0) && (down[i] <= 0))
+					continue;
+				StringBuilder builder = new StringBuilder();
+				if (!skipPrint)
+				{
+					builder.Append(paramname[i]);
+					builder.Append(' ');
+					builder.Append(param[i].ToString());
+					if (up[i] > 0)
+					{
+						builder.Append('+');
+						builder.Append(up[i].ToString());
+					}
+					if (down[i] > 0)
+					{
+						builder.Append('-');
+						builder.Append(down[i].ToString());
+					}
+				}
+				unchecked { param[i] += up[i] - down[i]; }
+				if (!skipPrint)
+				{
+					builder.Append('=');
+					builder.Append(param[i].ToString());
+					window.Print(builder.ToString());
+					window.NewLine();
+				}
+			}
+			for (int i = 0; i < up.Length; i++)
+				up[i] = 0;
+			for (int i = 0; i < down.Length; i++)
+				down[i] = 0;
+		}
+
+		private void setDefaultStain(CharacterData chara)
+		{
+			long[] array = chara.DataIntegerArray[(int)(VariableCode.STAIN & VariableCode.__LOWERCASE__)];
+			//STAINの配列要素数 < _REPLACE.CSVのSTAIN初期値の指定数の時エラーになるのを対処
+			if (array.Length >= Config.StainDefault.Count)
+			{
+				Config.StainDefault.CopyTo(array);
+				for (int i = Config.StainDefault.Count; i < array.Length; i++)
+					array[i] = 0;
+			}
+			else
+			{
+				for (int i = 0; i < array.Length; i++)
+					array[i] = Config.StainDefault[i];
+			}
+		}
+
+		public void SetDefaultStain(Int64 no)
+		{
+			if (no < 0 || no >= varData.CharacterList.Count)
+				throw new CodeEE("Attempted to refer to a character that does not exist");
+			CharacterData chara = varData.CharacterList[(int)no];
+			setDefaultStain(chara);
+		}
+
+		/// <summary>
+		/// RESULTに配列のサイズを代入。二次元配列ならRESULT:1に二番目のサイズを代入。三次元配列ならRESULT:1に二番目、RESULT:2に三番目のサイズを代入
+		/// </summary>
+		/// <param name="varID"></param>
+		/// <returns></returns>
+		public void VarSize(VariableToken varID)
+		{
+			Int64[] resultArray = RESULT_ARRAY;
+			if (varID.IsArray2D)
+			{
+				resultArray[0] = varID.GetLength(0);
+				resultArray[1] = varID.GetLength(1);
+			}
+			else if (varID.IsArray3D)
+			{
+				resultArray[0] = varID.GetLength(0);
+				resultArray[1] = varID.GetLength(1);
+				resultArray[2] = varID.GetLength(2);
+			}
+			else
+			{
+				resultArray[0] = varID.GetLength();
+			}
+		}
+
+		public bool ItemSales(Int64 itemNo)
+		{
+			Int64[] itemSales = ITEMSALES;
+			string[] itemNames = constant.GetCsvNameList(VariableCode.ITEMNAME);
+			if ((itemNo < 0) || (itemNo >= itemSales.Length) || (itemNo >= itemNames.Length))
+				return false;
+			int index = (int)itemNo;
+			return ((itemSales[index] != 0) && (itemNames[index] != null));
+		}
+
+		public bool BuyItem(Int64 itemNo)
+		{
+			if (!ItemSales(itemNo))
+				return false;
+			Int64[] itemPrice = constant.ItemPrice;
+			if (itemNo >= itemPrice.Length)
+				return false;
+			int index = (int)itemNo;
+			if (MONEY < itemPrice[index])
+				return false;
+			MONEY -= itemPrice[index];
+			ITEM[index]++;
+			BOUGHT = itemNo;
+			return true;
+		}
+
+
+		public void SetEncodingResult(int[] ary)
+		{
+			long[] resary = varData.DataIntegerArray[(int)(VariableCode.RESULT & VariableCode.__LOWERCASE__)];
+			resary[0] = ary.Length;
+			for (int i = 0; i < ary.Length; i++)
+				resary[i + 1] = ary[i];
+		}
+
+		#endregion
+
+		//ちーと
+		public void IamaMunchkin()
+		{
+			if ((MASTER < 0) || (MASTER >= varData.CharacterList.Count))
+				return;
+			varData.CharacterList[(int)MASTER].DataString[(int)(VariableCode.NAME & VariableCode.__LOWERCASE__)] = "イカサマ";
+			varData.CharacterList[(int)MASTER].DataString[(int)(VariableCode.CALLNAME & VariableCode.__LOWERCASE__)] = "イカサマ";
+			varData.CharacterList[(int)MASTER].DataString[(int)(VariableCode.NICKNAME & VariableCode.__LOWERCASE__)] = "イカサマ";
+
+		}
+
+		public void SetResultX(List<long> values)
+		{
+			for (int i = 0; i < values.Count; i++)
+			{
+				if (i >= varData.DataIntegerArray[(int)(VariableCode.RESULT & VariableCode.__LOWERCASE__)].Length)
+					return;
+				varData.DataIntegerArray[(int)(VariableCode.RESULT & VariableCode.__LOWERCASE__)][i] = values[i];
+			}
+		}
+
+		#region File操作
+
+
+		private string getSaveDataPathG() { return Config.SavDir + "global.sav"; }
+		private string getSaveDataPath(int index) { return string.Format("{0}save{1:00}.sav", Config.SavDir, index); }
+		private string getSaveDataPath(string s) { return string.Format("{0}save{1:00}.sav", Config.SavDir, s); }
+
+		private string getSaveDataPathV(int index) { return Program.DatDir + string.Format("var_{0:00}.dat", index); }
+		private string getSaveDataPathC(int index) { return Program.DatDir + string.Format("chara_{0:00}.dat", index); }
+		private string getSaveDataPathV(string s) { return Program.DatDir + "var_" + s + ".dat"; }
+		private string getSaveDataPathC(string s) { return Program.DatDir + "chara_" + s + ".dat"; }
+
+		/// <summary>
+		/// DatFolderが存在せず、かつ作成に失敗したらエラーを投げる
+		/// </summary>
+		/// <returns></returns>
+		public void CreateDatFolder()
+		{
+			if (Directory.Exists(Program.DatDir))
+				return;
+			try
+			{
+				Directory.CreateDirectory(Program.DatDir);
+			}
+			catch
+			{
+				MessageBox.Show("Failed to create dat folder");
+				throw new CodeEE("Failed to create dat folder");
+			}
+		}
+
+		public List<string> GetDatFiles(bool charadat, string pattern)
+		{
+			List<string> files = new List<string>();
+			if (!Directory.Exists(Program.DatDir))
+				return files;
+			string searchPattern = "var_" + pattern + ".dat";
+			if (charadat)
+				searchPattern = "chara_" + pattern + ".dat";
+			string[] pathes = Directory.GetFiles(Program.DatDir, searchPattern, SearchOption.TopDirectoryOnly);
+			foreach (string path in pathes)
+			{
+				if (!Path.GetExtension(path).Equals(".dat", StringComparison.OrdinalIgnoreCase))
+					continue;
+				string filename = Path.GetFileNameWithoutExtension(path);
+				if (charadat)
+					filename = filename.Substring(6);
+				else
+					filename = filename.Substring(4);
+				if (string.IsNullOrEmpty(filename))
+					continue;
+				files.Add(filename);
+			}
+			return files;
+		}
+
+		/// <summary>
+		/// 文字列がファイル名の一部として適切かどうか調べる
+		/// </summary>
+		/// <param name="datfilename"></param>
+		/// <returns>適切ならnull、不適切ならエラーメッセージ</returns>
+		public string CheckDatFilename(string datfilename)
+		{
+			if (string.IsNullOrEmpty(datfilename))
+				return "File name is not specified";
+			if (datfilename.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
+				return "Invalid character in file name";
+			return null;
+		}
+
+		public EraDataResult CheckData(string savename, EraSaveFileType type)
+		{
+			string filename = null;
+			switch (type)
+			{
+				case EraSaveFileType.Normal:
+					filename = getSaveDataPath(savename); break;
+				case EraSaveFileType.Global:
+					filename = getSaveDataPathG(); break;
+				case EraSaveFileType.Var:
+					filename = getSaveDataPathV(savename); break;
+				case EraSaveFileType.CharVar:
+					filename = getSaveDataPathC(savename); break;
+			}
+			return CheckDataByFilename(filename, type);
+		}
+
+		public EraDataResult CheckData(int saveIndex, EraSaveFileType type)
+		{
+			string filename = null;
+			switch (type)
+			{
+				case EraSaveFileType.Normal:
+					filename = getSaveDataPath(saveIndex); break;
+				case EraSaveFileType.Global:
+					filename = getSaveDataPathG(); break;
+				case EraSaveFileType.Var:
+					filename = getSaveDataPathV(saveIndex); break;
+				case EraSaveFileType.CharVar:
+					filename = getSaveDataPathC(saveIndex); break;
+			}
+			return CheckDataByFilename(filename, type);
+		}
+
+		public EraDataResult CheckDataByFilename(string filename, EraSaveFileType type)
+		{
+			EraDataResult result = new EraDataResult();
+			if (!File.Exists(filename))
+			{
+				result.State = EraDataState.FILENOTFOUND;
+				result.DataMes = "----";
+				return result;
+			}
+			FileStream fs = null;
+			EraBinaryDataReader bReader = null;
+			EraDataReader reader = null;
+			Int64 version = 0;
+			try
+			{
+				fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
+				bReader = EraBinaryDataReader.CreateReader(fs);
+				if (bReader == null)//eramaker形式
+				{
+					reader = new EraDataReader(fs);
+					if (!gamebase.UniqueCodeEqualTo(reader.ReadInt64()))
+					{
+						result.State = EraDataState.GAME_ERROR;
+						result.DataMes = "Attempted to load save data from a different game";
+						return result;
+					}
+					version = reader.ReadInt64();
+					if (!gamebase.CheckVersion(version))
+					{
+						result.State = EraDataState.VIRSION_ERROR;
+						result.DataMes = "Save data version is different";
+						return result;
+					}
+					result.State = EraDataState.OK;
+					result.DataMes = reader.ReadString();
+					return result;
+					//result.State = EraDataState.ETC_ERROR;
+					//result.DataMes = "セーブデータが壊れています";
+					//return result;
+				}
+				EraSaveFileType fileType = bReader.ReadFileType();
+				if (type != fileType)
+				{
+					result.State = EraDataState.ETC_ERROR;
+					result.DataMes = "Save data is corrupted";
+					return result;
+				}
+				if (!gamebase.UniqueCodeEqualTo(bReader.ReadInt64()))
+				{
+					result.State = EraDataState.GAME_ERROR;
+					result.DataMes = "Attempted to load save data from a different game";
+					return result;
+				}
+				version = bReader.ReadInt64();
+				if (!gamebase.CheckVersion(version))
+				{
+					result.State = EraDataState.VIRSION_ERROR;
+					result.DataMes = "Save data version is different";
+					return result;
+				}
+				result.State = EraDataState.OK;
+				result.DataMes = bReader.ReadString();
+				return result;
+			}
+			catch (FileEE fee)
+			{
+				result.State = EraDataState.ETC_ERROR;
+				result.DataMes = fee.Message;
+			}
+			catch (Exception)
+			{
+				result.State = EraDataState.ETC_ERROR;
+				result.DataMes = "An error has occurred while loading";
+			}
+			finally
+			{
+				if (reader != null)
+					reader.Close();
+				else if (bReader != null)
+					bReader.Close();
+				else if (fs != null)
+					fs.Close();
+			}
+			return result;
+		}
+
+		////これは理屈上VariableEvaluator上で動くはず
+		//public EraDataResult checkData(int saveIndex)
+		//{
+		//    string filename = getSaveDataPath(saveIndex);
+		//    EraDataResult result = new EraDataResult();
+		//    EraDataReader reader = null;
+		//    try
+		//    {
+		//        if (!File.Exists(filename))
+		//        {
+		//            result.State = EraDataState.FILENOTFOUND;
+		//            result.DataMes = "----";
+		//            return result;
+		//        }
+		//        reader = new EraDataReader(filename);
+		//        if (!gamebase.UniqueCodeEqualTo(reader.ReadInt64()))
+		//        {
+		//            result.State = EraDataState.GAME_ERROR;
+		//            result.DataMes = "Attempted to load save data from a different game";
+		//            return result;
+		//        }
+		//        Int64 version = reader.ReadInt64();
+		//        if (!gamebase.CheckVersion(version))
+		//        {
+		//            result.State = EraDataState.VIRSION_ERROR;
+		//            result.DataMes = "Save data version is different";
+		//            return result;
+		//        }
+		//        result.State = EraDataState.OK;
+		//        result.DataMes = reader.ReadString();
+		//        return result;
+		//    }
+		//    catch (FileEE fee)
+		//    {
+		//        result.State = EraDataState.ETC_ERROR;
+		//        result.DataMes = fee.Message;
+		//    }
+		//    catch (Exception)
+		//    {
+		//        result.State = EraDataState.ETC_ERROR;
+		//        result.DataMes = "読み込み中にエラーが発生しました";
+		//    }
+		//    finally
+		//    {
+		//        if (reader != null)
+		//            reader.Close();
+		//    }
+		//    return result;
+		//}
+
+		public void SaveChara(string savename, string savMes, int[] charas)
+		{
+			CreateDatFolder();
+			CheckDatFilename(savename);
+			string filepath = getSaveDataPathC(savename);
+			EraBinaryDataWriter bWriter = null;
+			FileStream fs = null;
+			try
+			{
+				Config.CreateSavDir();
+				fs = new FileStream(filepath, FileMode.Create, FileAccess.Write);
+				bWriter = new EraBinaryDataWriter(fs);
+				bWriter.WriteHeader();
+				bWriter.WriteFileType(EraSaveFileType.CharVar);
+				bWriter.WriteInt64(gamebase.ScriptUniqueCode);
+				bWriter.WriteInt64(gamebase.ScriptVersion);
+				bWriter.WriteString(savMes);
+				bWriter.WriteInt64(charas.Length);//保存するキャラ数
+				for (int i = 0; i < charas.Length; i++)
+				{
+					varData.CharacterList[charas[i]].SaveToStreamBinary(bWriter, varData);
+				}
+				bWriter.WriteEOF();
+				//RESULT = 1;
+			}
+			//catch (Exception)
+			//{
+			//	throw new CodeEE("セーブ中にエラーが発生しました");
+			//}
+			finally
+			{
+				if (bWriter != null)
+					bWriter.Close();
+				else if (fs != null)
+					fs.Close();
+			}
+		}
+
+		public void LoadChara(string savename)
+		{
+			string filepath = getSaveDataPathC(savename);
+			RESULT = 0;
+			if (!File.Exists(filepath))
+				return;
+			EraBinaryDataReader bReader = null;
+			FileStream fs = null;
+			try
+			{
+				List<CharacterData> addCharaList = new List<CharacterData>();
+				fs = new FileStream(filepath, FileMode.Open, FileAccess.Read);
+				bReader = EraBinaryDataReader.CreateReader(fs);
+				if (bReader == null)
+					return;
+				if (bReader.ReadFileType() != EraSaveFileType.CharVar)
+					return;
+
+				if (!gamebase.UniqueCodeEqualTo(bReader.ReadInt64()))
+					return;
+				Int64 version = bReader.ReadInt64();
+				if (!gamebase.CheckVersion(version))
+					return;
+				bReader.ReadString();//saveMes
+				Int64 loadnum = bReader.ReadInt64();
+				for (int i = 0; i < loadnum; i++)
+				{
+					CharacterData chara = new CharacterData(constant, varData);
+					chara.LoadFromStreamBinary(bReader);
+					addCharaList.Add(chara);
+				}
+				varData.CharacterList.AddRange(addCharaList);
+				RESULT = 1;
+			}
+			//catch (Exception)
+			//{
+			//	return;
+			//}
+			finally
+			{
+				if (bReader != null)
+					bReader.Close();
+				else if (fs != null)
+					fs.Close();
+			}
+		}
+
+	    public bool SaveGlobal()
+		{
+			string filepath = getSaveDataPathG();
+			EraDataWriter writer = null;
+			EraBinaryDataWriter bWriter = null;
+			FileStream fs = null;
+			try
+			{
+				Config.CreateSavDir();
+				fs = new FileStream(filepath, FileMode.Create, FileAccess.Write);
+				if (Config.SystemSaveInBinary)
+				{
+
+					bWriter = new EraBinaryDataWriter(fs);
+					bWriter.WriteHeader();
+					bWriter.WriteFileType(EraSaveFileType.Global);
+					bWriter.WriteInt64(gamebase.ScriptUniqueCode);
+					bWriter.WriteInt64(gamebase.ScriptVersion);
+					bWriter.WriteString("");//saveMes
+					varData.SaveGlobalToStreamBinary(bWriter);
+					bWriter.WriteEOF();
+				}
+				else
+				{
+					writer = new EraDataWriter(fs);
+					writer.Write(gamebase.ScriptUniqueCode);
+					writer.Write(gamebase.ScriptVersion);
+					varData.SaveGlobalToStream(writer);
+					writer.EmuStart();
+					varData.SaveGlobalToStream1808(writer);
+				}
+			}
+			//catch (SystemException)
+			//{
+			//	throw new CodeEE("グローバルデータの保存中にエラーが発生しました");
+			//	//console.PrintError(
+			//	//console.NewLine();
+			//	//return false;
+			//}
+			finally
+			{
+				if (writer != null)
+					writer.Close();
+				else if (bWriter != null)
+					bWriter.Close();
+				else if (fs != null)
+					fs.Close();
+			}
+			return true;
+		}
+
+		public bool LoadGlobal()
+		{
+			string filepath = getSaveDataPathG();
+			if (!File.Exists(filepath))
+				return false;
+			EraDataReader reader = null;
+			EraBinaryDataReader bReader = null;
+			FileStream fs = null;
+			try
+			{
+				fs = new FileStream(filepath, FileMode.Open, FileAccess.Read);
+				bReader = EraBinaryDataReader.CreateReader(fs);
+				if (bReader != null)
+				{
+					EraSaveFileType fileType = bReader.ReadFileType();
+					if (fileType != EraSaveFileType.Global)
+						return false;
+					if (!gamebase.UniqueCodeEqualTo(bReader.ReadInt64()))
+						return false;
+					Int64 version = bReader.ReadInt64();
+					if (!gamebase.CheckVersion(version))
+						return false;
+					bReader.ReadString();//saveMes
+					varData.LoadFromStreamBinary(bReader);
+				}
+				else
+				{
+					reader = new EraDataReader(fs);
+					if (!gamebase.UniqueCodeEqualTo(reader.ReadInt64()))
+						return false;
+					Int64 version = reader.ReadInt64();
+					if (!gamebase.CheckVersion(version))
+						return false;
+					varData.LoadGlobalFromStream(reader);
+					if (reader.SeekEmuStart())
+					{
+						varData.LoadGlobalFromStream1808(reader);
+					}
+				}
+				return true;
+			}
+			catch
+			{
+				return false;
+			}
+			finally
+			{
+				if (reader != null)
+					reader.Close();
+				else if (bReader != null)
+					bReader.Close();
+				else if (fs != null)
+					fs.Close();
+			}
+		}
+
+		public void SaveToStreamBinary(EraBinaryDataWriter bWriter, string saveDataText)
+		{
+			bWriter.WriteHeader();
+			bWriter.WriteFileType(EraSaveFileType.Normal);
+			bWriter.WriteInt64(gamebase.ScriptUniqueCode);
+			bWriter.WriteInt64(gamebase.ScriptVersion);
+			bWriter.WriteString(saveDataText);
+			bWriter.WriteInt64(varData.CharacterList.Count);
+			for (int i = 0; i < varData.CharacterList.Count; i++)
+			{
+				varData.CharacterList[i].SaveToStreamBinary(bWriter, varData);
+			}
+			varData.SaveToStreamBinary(bWriter);
+			bWriter.WriteEOF();
+		}
+
+		public void LoadFromStreamBinary(EraBinaryDataReader bReader)
+		{
+			EraSaveFileType fileType = bReader.ReadFileType();
+			if (fileType != EraSaveFileType.Normal)
+				throw new FileEE("セーブデータが壊れています");
+			if (!gamebase.UniqueCodeEqualTo(bReader.ReadInt64()))
+				throw new FileEE("Attempted to load save data from a different game");
+			Int64 version = bReader.ReadInt64();
+			if (!gamebase.CheckVersion(version))
+				throw new FileEE("Save data version is different");
+			string text = bReader.ReadString();//PUTFORM
+			varData.SetDefaultValue(constant);
+			varData.SetDefaultLocalValue();
+			varData.LastLoadVersion = version;
+			//varData.LastLoadNo = dataIndex;
+			varData.LastLoadText = text;
+
+			int charaCount = (int)bReader.ReadInt64();
+			varData.CharacterList.Clear();
+			for (int i = 0; i < charaCount; i++)
+			{
+				CharacterData chara = new CharacterData(constant, varData);
+				varData.CharacterList.Add(chara);
+				chara.LoadFromStreamBinary(bReader);
+			}
+			varData.LoadFromStreamBinary(bReader);
+		}
+
+		public bool SaveTo(int saveIndex, string saveText)
+		{
+			string filepath = getSaveDataPath(saveIndex);
+			FileStream fs = null;
+		    EraBinaryDataWriter bWriter = null;
+			try
+			{
+				Config.CreateSavDir();
+				fs = new FileStream(filepath, FileMode.Create, FileAccess.Write);
+                // So this used to check for a config option as to whether it should save in binary format or not
+                // But since there's no way to set it and all games use binary by default I took it out because it was bad --Sworve
+				bWriter = new EraBinaryDataWriter(fs);
+				SaveToStreamBinary(bWriter, saveText);
+				return true;
+			}
+			catch (Exception)
+			{
+				return false;
+			}
+			finally
+			{
+                bWriter?.Close();
+			    fs?.Close();
+			}
+		}
+
+		public bool LoadFrom(int dataIndex)
+		{
+			string filepath = getSaveDataPath(dataIndex);
+			if (!File.Exists(filepath))
+				throw new ExeEE("存在しないパスを呼び出した");
+			EraBinaryDataReader bReader = null;
+			FileStream fs = null;
+			try
+			{
+				fs = new FileStream(filepath, FileMode.Open, FileAccess.Read);
+				bReader = EraBinaryDataReader.CreateReader(fs);
+				LoadFromStreamBinary(bReader);
+				varData.LastLoadNo = dataIndex;
+			}
+			finally
+			{
+				bReader?.Close();
+				fs?.Close();
+			}
+			return true;
+		}
+
+		public void DelData(int dataIndex)
+		{
+			string filepath = getSaveDataPath(dataIndex);
+			if (!File.Exists(filepath))
+				return;
+			FileAttributes att = File.GetAttributes(filepath);
+			if ((att & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
+				throw new CodeEE("Specified file \"" + filepath + "\" cannot be deleted because it is set to read only");
+			//{
+
+			//    console.PrintError("指定されたファイル\"" + filepath + "\"は読み込み専用のため削除できません");
+			//    return;
+			//}
+			File.Delete(filepath);
+		}
+
+
+
+		#endregion
+		#region IDisposable メンバ
+
+		public void Dispose()
+		{
+			varData.Dispose();
+		}
+
+		#endregion
+		#region Property
+		public Int64[] RESULT_ARRAY => varData.DataIntegerArray[(int)(VariableCode.RESULT & VariableCode.__LOWERCASE__)];
+
+		public Int64 RESULT
+		{
+			get => varData.DataIntegerArray[(int)(VariableCode.RESULT & VariableCode.__LOWERCASE__)][0];
+			set { varData.DataIntegerArray[(int)(VariableCode.RESULT & VariableCode.__LOWERCASE__)][0] = value; }
+		}
+		public Int64 COUNT
+		{
+			get => varData.DataIntegerArray[(int)(VariableCode.COUNT & VariableCode.__LOWERCASE__)][0];
+			set { varData.DataIntegerArray[(int)(VariableCode.COUNT & VariableCode.__LOWERCASE__)][0] = value; }
+		}
+		public string RESULTS
+		{
+			get
+			{
+				string ret = varData.DataStringArray[(int)(VariableCode.RESULTS & VariableCode.__LOWERCASE__)][0];
+				if (ret == null)
+					return "";
+				return ret;
+			}
+			set => varData.DataStringArray[(int)(VariableCode.RESULTS & VariableCode.__LOWERCASE__)][0] = value;
+		}
+		public string[] RESULTS_ARRAY => varData.DataStringArray[(int)(VariableCode.RESULTS & VariableCode.__LOWERCASE__)];
+
+		public Int64 TARGET
+		{
+			get => varData.DataIntegerArray[(int)(VariableCode.TARGET & VariableCode.__LOWERCASE__)][0];
+			set { varData.DataIntegerArray[(int)(VariableCode.TARGET & VariableCode.__LOWERCASE__)][0] = value; }
+		}
+		public Int64[] SELECTCOM_ARRAY => varData.DataIntegerArray[(int)(VariableCode.SELECTCOM & VariableCode.__LOWERCASE__)];
+
+		public Int64 SELECTCOM
+		{
+			get => varData.DataIntegerArray[(int)(VariableCode.SELECTCOM & VariableCode.__LOWERCASE__)][0];
+			set { varData.DataIntegerArray[(int)(VariableCode.SELECTCOM & VariableCode.__LOWERCASE__)][0] = value; }
+		}
+		public string[] ITEMNAME => constant.GetCsvNameList(VariableCode.ITEMNAME);
+
+		public Int64[] ITEMSALES => varData.DataIntegerArray[(int)(VariableCode.ITEMSALES & VariableCode.__LOWERCASE__)];
+
+		public Int64[] ITEMPRICE => constant.ItemPrice;
+
+		private Int64[] ITEM => varData.DataIntegerArray[(int)(VariableCode.ITEM & VariableCode.__LOWERCASE__)];
+
+		public Int64[] RANDDATA => varData.DataIntegerArray[(int)(VariableCode.RANDDATA & VariableCode.__LOWERCASE__)];
+
+		public string SAVEDATA_TEXT
+		{
+			get => varData.DataString[(int)(VariableCode.SAVEDATA_TEXT & VariableCode.__LOWERCASE__)];
+			set { varData.DataString[(int)(VariableCode.SAVEDATA_TEXT & VariableCode.__LOWERCASE__)] = value; }
+		}
+		public Int64 CHARANUM => varData.CharacterList.Count;
+
+
+		private Int64 get_Variable_canforbid(VariableCode code)
+		{
+			long[] array = varData.DataIntegerArray[(int)(code & VariableCode.__LOWERCASE__)];
+			if (array.Length == 0)
+				return -1;
+			return array[0];
+		}
+		private void set_Variable_canforbid(VariableCode code, Int64 value)
+		{
+			long[] array = varData.DataIntegerArray[(int)(code & VariableCode.__LOWERCASE__)];
+			if (array.Length == 0)
+				return;
+			array[0] = value;
+		}
+
+		public Int64 MASTER
+		{
+			get => get_Variable_canforbid(VariableCode.MASTER);
+			set { set_Variable_canforbid(VariableCode.MASTER, value); }
+		}
+		public Int64 ASSI
+		{
+			get => get_Variable_canforbid(VariableCode.ASSI);
+			set { set_Variable_canforbid(VariableCode.ASSI, value); }
+		}
+		public Int64 ASSIPLAY
+		{
+			set => set_Variable_canforbid(VariableCode.ASSIPLAY, value);
+		}
+		public Int64 PREVCOM
+		{
+			get => get_Variable_canforbid(VariableCode.PREVCOM);
+			set { set_Variable_canforbid(VariableCode.PREVCOM, value); }
+		}
+		public Int64 NEXTCOM
+		{
+			get => get_Variable_canforbid(VariableCode.NEXTCOM);
+			set { set_Variable_canforbid(VariableCode.NEXTCOM, value); }
+		}
+		private Int64 MONEY
+		{
+			get => get_Variable_canforbid(VariableCode.MONEY);
+			set { set_Variable_canforbid(VariableCode.MONEY, value); }
+		}
+
+		private Int64 BOUGHT
+		{
+			set => set_Variable_canforbid(VariableCode.BOUGHT, value);
+		}
+
+		//public Int64 MASTER
+		//{
+		//	get { return varData.DataIntegerArray[(int)(VariableCode.MASTER & VariableCode.__LOWERCASE__)][0]; }
+		//	set { varData.DataIntegerArray[(int)(VariableCode.MASTER & VariableCode.__LOWERCASE__)][0] = value; }
+		//}
+		//public Int64 ASSI
+		//{
+		//	get { return varData.DataIntegerArray[(int)(VariableCode.ASSI & VariableCode.__LOWERCASE__)][0]; }
+		//	set { varData.DataIntegerArray[(int)(VariableCode.ASSI & VariableCode.__LOWERCASE__)][0] = value; }
+		//}
+		//public Int64 ASSIPLAY
+		//{
+		//	//get { return varData.DataIntegerArray[(int)(VariableCode.ASSIPLAY & VariableCode.__LOWERCASE__)][0]; }
+		//	set { varData.DataIntegerArray[(int)(VariableCode.ASSIPLAY & VariableCode.__LOWERCASE__)][0] = value; }
+		//}
+		//public Int64 PREVCOM
+		//{
+		//	//get { return varData.DataIntegerArray[(int)(VariableCode.PREVCOM & VariableCode.__LOWERCASE__)][0]; }
+		//	set { varData.DataIntegerArray[(int)(VariableCode.PREVCOM & VariableCode.__LOWERCASE__)][0] = value; }
+		//}
+		//public Int64 NEXTCOM
+		//{
+		//	get { return varData.DataIntegerArray[(int)(VariableCode.NEXTCOM & VariableCode.__LOWERCASE__)][0]; }
+		//	set { varData.DataIntegerArray[(int)(VariableCode.NEXTCOM & VariableCode.__LOWERCASE__)][0] = value; }
+		//}
+		//private Int64 MONEY
+		//{
+		//	get { return varData.DataIntegerArray[(int)(VariableCode.MONEY & VariableCode.__LOWERCASE__)][0]; }
+		//	set { varData.DataIntegerArray[(int)(VariableCode.MONEY & VariableCode.__LOWERCASE__)][0] = value; }
+		//}
+
+		//private Int64 BOUGHT
+		//{
+		//	//get { return varData.DataIntegerArray[(int)(VariableCode.BOUGHT & VariableCode.__LOWERCASE__)][0]; }
+		//	set { varData.DataIntegerArray[(int)(VariableCode.BOUGHT & VariableCode.__LOWERCASE__)][0] = value; }
+		//}
+		#endregion
+
+	}
+}

+ 245 - 0
NTERA/Game/GameData/Variable/VariableIdentifier.cs

@@ -0,0 +1,245 @@
+using System;
+using System.Collections.Generic;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameData.Variable
+{
+	//1756 全ての機能をVariableTokenとManagerに委譲、消滅
+	//……しようと思ったがConstantDataから参照されているので捨て切れなかった。
+	/// <summary>
+	/// VariableCodeのラッパー
+	/// </summary>
+	internal sealed class VariableIdentifier
+	{
+		private VariableIdentifier(VariableCode code)
+		{ this.code = code; }
+		private VariableIdentifier(VariableCode code, string scope)
+		{ this.code = code; this.scope = scope; }
+		readonly VariableCode code;
+		readonly string scope;
+		public VariableCode Code => code;
+
+		public string Scope => scope;
+
+		public int CodeInt => (int)(code & VariableCode.__LOWERCASE__);
+
+		public VariableCode CodeFlag => code & VariableCode.__UPPERCASE__;
+		//public int Dimension
+		//{
+		//    get
+		//    {
+		//        int dim = 0;
+		//        if ((code & VariableCode.__ARRAY_1D__) == VariableCode.__ARRAY_1D__)
+		//            dim++;
+		//        if ((code & VariableCode.__CHARACTER_DATA__) == VariableCode.__CHARACTER_DATA__)
+		//            dim++;
+		//        if ((code & VariableCode.__ARRAY_2D__) == VariableCode.__ARRAY_2D__)
+		//            dim += 2;
+		//        return dim;
+		//    }
+		//}
+
+		public bool IsNull => code == VariableCode.__NULL__;
+
+		public bool IsCharacterData => ((code & VariableCode.__CHARACTER_DATA__) == VariableCode.__CHARACTER_DATA__);
+
+		public bool IsInteger => ((code & VariableCode.__INTEGER__) == VariableCode.__INTEGER__);
+
+		public bool IsString => ((code & VariableCode.__STRING__) == VariableCode.__STRING__);
+
+		public bool IsArray1D => ((code & VariableCode.__ARRAY_1D__) == VariableCode.__ARRAY_1D__);
+
+		public bool IsArray2D => ((code & VariableCode.__ARRAY_2D__) == VariableCode.__ARRAY_2D__);
+
+		public bool IsArray3D => ((code & VariableCode.__ARRAY_3D__) == VariableCode.__ARRAY_3D__);
+
+		public bool Readonly => ((code & VariableCode.__UNCHANGEABLE__) == VariableCode.__UNCHANGEABLE__);
+
+		public bool IsCalc => ((code & VariableCode.__CALC__) == VariableCode.__CALC__);
+
+		public bool IsLocal => ((code & VariableCode.__LOCAL__) == VariableCode.__LOCAL__);
+
+		//public bool IsConstant
+		//{
+		//    get
+		//    {
+		//        return ((code & VariableCode.__CONSTANT__) == VariableCode.__CONSTANT__);
+		//    }
+		//}
+        public bool CanForbid => ((code & VariableCode.__CAN_FORBID__) == VariableCode.__CAN_FORBID__);
+		static readonly Dictionary<string, VariableCode> nameDic = new Dictionary<string, VariableCode>();
+		static readonly Dictionary<string, VariableCode> localvarNameDic = new Dictionary<string, VariableCode>();
+		static readonly Dictionary<VariableCode, List<VariableCode>> extSaveListDic = new Dictionary<VariableCode, List<VariableCode>>();
+
+		public static Dictionary<string, VariableCode> GetVarNameDic()
+		{
+			return nameDic;
+		}
+
+
+		static VariableIdentifier()
+		{
+			Array array = Enum.GetValues(typeof(VariableCode));
+
+			nameDic.Add(VariableCode.__FILE__.ToString(), VariableCode.__FILE__);
+			nameDic.Add(VariableCode.__LINE__.ToString(), VariableCode.__LINE__);
+			nameDic.Add(VariableCode.__FUNCTION__.ToString(), VariableCode.__FUNCTION__);
+			foreach (object name in array)
+			{
+				VariableCode code = (VariableCode)name;
+				string key = code.ToString();
+				if ((key == null) || (key.StartsWith("__") && key.EndsWith("__")))
+					continue;
+				if (Config.ICVariable)
+					key = key.ToUpper();
+				if (nameDic.ContainsKey(key))
+					continue;
+#if DEBUG
+				if ((code & VariableCode.__ARRAY_2D__) == VariableCode.__ARRAY_2D__)
+				{
+					if ((code & VariableCode.__ARRAY_1D__) == VariableCode.__ARRAY_1D__)
+						throw new ExeEE("ARRAY2DとARRAY1Dは排他");
+				}
+				if (((code & VariableCode.__INTEGER__) != VariableCode.__INTEGER__)
+					&& ((code & VariableCode.__STRING__) != VariableCode.__STRING__))
+						throw new ExeEE("INTEGERとSTRINGのどちらかは必須");
+				if (((code & VariableCode.__INTEGER__) == VariableCode.__INTEGER__)
+					&& ((code & VariableCode.__STRING__) == VariableCode.__STRING__))
+						throw new ExeEE("INTEGERとSTRINGは排他");
+				if((code & VariableCode.__EXTENDED__) != VariableCode.__EXTENDED__)
+				{
+					if ((code & VariableCode.__SAVE_EXTENDED__) == VariableCode.__SAVE_EXTENDED__)
+							throw new ExeEE("SAVE_EXTENDEDにはEXTENDEDフラグ必須");
+					if ((code & VariableCode.__LOCAL__) == VariableCode.__LOCAL__)
+							throw new ExeEE("LOCALにはEXTENDEDフラグ必須");
+					if ((code & VariableCode.__GLOBAL__) == VariableCode.__GLOBAL__)
+							throw new ExeEE("GLOBALにはEXTENDEDフラグ必須");
+					if ((code & VariableCode.__ARRAY_2D__) == VariableCode.__ARRAY_2D__)
+							throw new ExeEE("ARRAY2DにはEXTENDEDフラグ必須");
+				}
+				if (((code & VariableCode.__SAVE_EXTENDED__) == VariableCode.__SAVE_EXTENDED__)
+					&& ((code & VariableCode.__UNCHANGEABLE__) == VariableCode.__UNCHANGEABLE__))
+						throw new ExeEE("CALCとSAVE_EXTENDEDは排他");
+				if (((code & VariableCode.__SAVE_EXTENDED__) == VariableCode.__SAVE_EXTENDED__)
+					&& ((code & VariableCode.__CALC__) == VariableCode.__CALC__))
+						throw new ExeEE("UNCHANGEABLEとSAVE_EXTENDEDは排他");
+				if (((code & VariableCode.__SAVE_EXTENDED__) == VariableCode.__SAVE_EXTENDED__)
+					&& ((code & VariableCode.__ARRAY_2D__) == VariableCode.__ARRAY_2D__)
+					&& ((code & VariableCode.__STRING__) == VariableCode.__STRING__))
+						throw new ExeEE("STRINGかつARRAY2DのSAVE_EXTENDEDは未実装");
+#endif
+				nameDic.Add(key, code);
+				////セーブが必要な変数リストの作成
+
+				////__SAVE_EXTENDED__フラグ持ち
+				//if ((code & VariableCode.__SAVE_EXTENDED__) == VariableCode.__SAVE_EXTENDED__)
+				//{
+				//    if ((code & VariableCode.__CHARACTER_DATA__) == VariableCode.__CHARACTER_DATA__)
+				//        charaSaveDataList.Add(code);
+				//    else
+				//        saveDataList.Add(code);
+				//}
+				//else if ( ((code & VariableCode.__EXTENDED__) != VariableCode.__EXTENDED__)
+				//    && ((code & VariableCode.__CALC__) != VariableCode.__CALC__)
+				//    && ((code & VariableCode.__UNCHANGEABLE__) != VariableCode.__UNCHANGEABLE__)
+				//    && ((code & VariableCode.__LOCAL__) != VariableCode.__LOCAL__)
+				//    && (!key.StartsWith("NOTUSE_")) )
+				//{//eramaker由来の変数でセーブするもの
+
+				//    VariableCode flag = code & (VariableCode.__ARRAY_1D__ | VariableCode.__ARRAY_2D__ | VariableCode.__ARRAY_3D__ | VariableCode.__STRING__ | VariableCode.__INTEGER__ | VariableCode.__CHARACTER_DATA__);
+				//    int codeInt = (int)VariableCode.__LOWERCASE__ & (int)code;
+				//    switch (flag)
+				//    {
+				//        case VariableCode.__CHARACTER_DATA__ | VariableCode.__INTEGER__:
+				//            if (codeInt < (int)VariableCode.__COUNT_SAVE_CHARACTER_INTEGER__)
+				//                charaSaveDataList.Add(code);
+				//            break;
+				//        case VariableCode.__CHARACTER_DATA__ | VariableCode.__STRING__:
+				//            if (codeInt < (int)VariableCode.__COUNT_SAVE_CHARACTER_STRING__)
+				//                charaSaveDataList.Add(code);
+				//            break;
+				//        case VariableCode.__CHARACTER_DATA__ | VariableCode.__INTEGER__ | VariableCode.__ARRAY_1D__:
+				//            if (codeInt < (int)VariableCode.__COUNT_SAVE_CHARACTER_INTEGER_ARRAY__)
+				//                charaSaveDataList.Add(code);
+				//            break;
+				//        case VariableCode.__CHARACTER_DATA__ | VariableCode.__STRING__ | VariableCode.__ARRAY_1D__:
+				//            if (codeInt < (int)VariableCode.__COUNT_SAVE_CHARACTER_STRING_ARRAY__)
+				//                charaSaveDataList.Add(code);
+				//            break;
+				//        case VariableCode.__INTEGER__:
+				//            if (codeInt < (int)VariableCode.__COUNT_SAVE_INTEGER__)
+				//                saveDataList.Add(code);
+				//            break;
+				//        case VariableCode.__STRING__:
+				//            if (codeInt < (int)VariableCode.__COUNT_SAVE_STRING__)
+				//                saveDataList.Add(code);
+				//            break;
+				//        case VariableCode.__INTEGER__ | VariableCode.__ARRAY_1D__:
+				//            if (codeInt < (int)VariableCode.__COUNT_SAVE_INTEGER_ARRAY__)
+				//                saveDataList.Add(code);
+				//            break;
+				//        case VariableCode.__STRING__ | VariableCode.__ARRAY_1D__:
+				//            if (codeInt < (int)VariableCode.__COUNT_SAVE_STRING_ARRAY__)
+				//                saveDataList.Add(code);
+				//            break;
+				//    }
+				//}
+
+				
+				if ((code & VariableCode.__LOCAL__) == VariableCode.__LOCAL__)
+					localvarNameDic.Add(key, code);
+				if ((code & VariableCode.__SAVE_EXTENDED__) == VariableCode.__SAVE_EXTENDED__)
+				{
+					VariableCode flag = code &
+						(VariableCode.__ARRAY_1D__ | VariableCode.__ARRAY_2D__ | VariableCode.__ARRAY_3D__ | VariableCode.__CHARACTER_DATA__ | VariableCode.__STRING__ | VariableCode.__INTEGER__);
+					if (!extSaveListDic.ContainsKey(flag))
+						extSaveListDic.Add(flag, new List<VariableCode>());
+					extSaveListDic[flag].Add(code);
+				}
+			}
+		}
+
+		public static List<VariableCode> GetExtSaveList(VariableCode flag)
+		{
+			VariableCode gFlag = flag &
+				(VariableCode.__ARRAY_1D__ | VariableCode.__ARRAY_2D__ | VariableCode.__ARRAY_3D__ | VariableCode.__CHARACTER_DATA__ | VariableCode.__STRING__ | VariableCode.__INTEGER__);
+			if (!extSaveListDic.ContainsKey(gFlag))
+				return new List<VariableCode>();
+			return extSaveListDic[gFlag];
+		}
+
+		public static VariableIdentifier GetVariableId(VariableCode code)
+		{
+			return new VariableIdentifier(code);
+		}
+
+		public static VariableIdentifier GetVariableId(string key)
+		{
+			return GetVariableId(key, null);
+		}
+		public static VariableIdentifier GetVariableId(string key, string subStr)
+		{
+			VariableCode ret = VariableCode.__NULL__;
+			if (string.IsNullOrEmpty(key))
+				return null;
+			if (Config.ICVariable)
+				key = key.ToUpper();
+			if (subStr != null)
+			{
+				if (Config.ICFunction)
+					subStr = subStr.ToUpper();
+				if (localvarNameDic.TryGetValue(key, out ret))
+					return new VariableIdentifier(ret, subStr);
+				if (nameDic.ContainsKey(key))
+					throw new CodeEE("ローカル変数でない変数" + key + "に対して@が使われました");
+				throw new CodeEE("@の使い方が不正です");
+			}
+			nameDic.TryGetValue(key, out ret);
+			return new VariableIdentifier(ret);
+		}
+		public override string ToString()
+		{
+			return code.ToString();
+		}
+	}
+}

+ 108 - 0
NTERA/Game/GameData/Variable/VariableLocal.cs

@@ -0,0 +1,108 @@
+using System.Collections.Generic;
+using MinorShift.Emuera.GameProc;
+
+namespace MinorShift.Emuera.GameData.Variable
+{
+	internal delegate LocalVariableToken CreateLocalVariableToken(VariableCode varCode, string subKey, int size);
+	internal sealed class VariableLocal
+	{
+		public VariableLocal(VariableCode varCode, int size, CreateLocalVariableToken creater)
+		{
+			this.size = size;
+			this.varCode = varCode;
+			this.creater = creater;
+		}
+		readonly int size;
+		public bool IsForbid => size == 0;
+
+		VariableCode varCode;
+		//VariableData varData;
+		CreateLocalVariableToken creater;
+		private readonly Dictionary<string, LocalVariableToken> localVarTokens = new Dictionary<string, LocalVariableToken>();
+		public LocalVariableToken GetExistLocalVariableToken(string subKey)
+		{
+			LocalVariableToken ret = null;
+			if (localVarTokens.TryGetValue(subKey, out ret))
+				return ret;
+			return ret;
+		}
+
+        public int GetDefaultSize()
+        {
+            return size;
+        }
+
+        public LocalVariableToken GetNewLocalVariableToken(string subKey, FunctionLabelLine func)
+        {
+            LocalVariableToken ret = null;
+            int newSize = 0;
+            if (varCode == VariableCode.LOCAL)
+                newSize = func.LocalLength;
+            else if (varCode == VariableCode.LOCALS)
+                newSize = func.LocalsLength;
+            else if (varCode == VariableCode.ARG)
+                newSize = func.ArgLength;
+            else if (varCode == VariableCode.ARGS)
+                newSize = func.ArgsLength;
+			if (newSize > 0)
+			{
+				if((newSize < size) && ((varCode == VariableCode.ARG) || (varCode == VariableCode.ARGS)))
+					newSize = size;
+				ret = creater(varCode, subKey, newSize);
+			}
+			else if (newSize == 0)
+				ret = creater(varCode, subKey, size);
+			else
+			{
+				ret = creater(varCode, subKey, size);
+				LogicalLine line = GlobalStatic.Process.GetScaningLine();
+                if (line != null)
+                {
+                    if (!func.IsSystem)
+						ParserMediator.Warn("関数宣言に引数変数\"" + varCode + "\"が使われていない関数中で\"" + varCode + "\"が使われています(関数の引数以外の用途に使うことは推奨されません。代わりに#DIMの使用を検討してください)", line, 1, false, false);
+                    else
+						ParserMediator.Warn("システム関数" + func.LabelName + "中で\"" + varCode + "\"が使われています(関数の引数以外の用途に使うことは推奨されません。代わりに#DIMの使用を検討してください)", line, 1, false, false);
+                }
+				//throw new CodeEE("この関数に引数変数\"" + varCode + "\"は定義されていません");
+			}
+            localVarTokens.Add(subKey, ret);
+            return ret;
+        }
+
+        public void ResizeLocalVariableToken(string subKey, int newSize)
+        {
+            LocalVariableToken ret = null;
+            if (localVarTokens.TryGetValue(subKey, out ret))
+            {
+                if (size < newSize)
+                    ret.resize(newSize);
+                else
+                    ret.resize(size);
+            }
+            else
+            {
+                if (newSize > size)
+                    ret = creater(varCode, subKey, newSize);
+                else if (newSize == 0)
+                    ret = creater(varCode, subKey, size);
+                else
+                    return;
+                localVarTokens.Add(subKey, ret);
+            }
+        }
+
+        public void Clear()
+		{
+			localVarTokens.Clear();
+		}
+
+        public void SetDefault()
+		{
+			foreach (KeyValuePair<string, LocalVariableToken> pair in localVarTokens)
+				pair.Value.SetDefault();
+		}
+    }
+
+    
+    
+}

+ 197 - 0
NTERA/Game/GameData/Variable/VariableParser.cs

@@ -0,0 +1,197 @@
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameData.Variable
+{
+	internal static class VariableParser
+	{
+		public static void Initialize()
+		{
+			ZeroTerm = new SingleTerm(0);
+			IOperandTerm[] zeroArgs = { ZeroTerm };
+			TARGET = new VariableTerm(GlobalStatic.VariableData.GetSystemVariableToken("TARGET"), zeroArgs);
+		}
+
+		public static SingleTerm ZeroTerm { get; private set; }
+		public static VariableTerm TARGET { get; private set; }
+
+		public static bool IsVariable(string ids)
+		{
+			if (string.IsNullOrEmpty(ids))
+				return false;
+			string[] idlist = ids.Split(':');
+			//idlist = synonym.ApplySynonym(idlist);
+			VariableToken id = GlobalStatic.IdentifierDictionary.GetVariableToken(idlist[0], null, false);
+			return id != null;
+		}
+
+		///// <summary>
+		///// まだ最初の識別子を読んでいない状態から決め打ちで変数を解読する
+		///// </summary>
+		///// <param name="st"></param>
+		///// <returns></returns>
+		//public static VariableTerm ReduceVariable(WordCollection wc)
+		//{
+		//    IdentifierWord id = wc.Current as IdentifierWord;
+		//    if (id == null)
+		//        return null;
+		//    wc.ShiftNext();
+		//    VariableToken vid = ExpressionParser.ReduceVariableIdentifier(wc, id.Code);
+		//    if (vid == null)
+		//        throw new CodeEE("\"" + id.Code + "\" cannot be interpreted");
+		//    return ReduceVariable(vid, wc);
+		//}
+
+		/// <summary>
+		/// 識別子を読み終えた状態からの解析
+		/// </summary>
+		/// <param name="st"></param>
+		/// <returns></returns>
+		public static VariableTerm ReduceVariable(VariableToken id, WordCollection wc)
+		{
+			IOperandTerm operand = null;
+			IOperandTerm op1 = null;
+			IOperandTerm op2 = null;
+			IOperandTerm op3 = null;
+			int i = 0;
+			while (true)
+			{
+				if (wc.Current.Type != ':')
+					break;
+				if (i >= 3)
+					throw new CodeEE(id.Code + " Too many arguments");
+				wc.ShiftNext();
+
+				operand = ExpressionParser.ReduceVariableArgument(wc, id.Code);
+				if (i == 0)
+					op1 = operand;
+				else if (i == 1)
+					op2 = operand;
+				else if (i == 2)
+					op3 = operand;
+				i++;
+			}
+			return ReduceVariable(id, op1, op2, op3);
+
+		}
+
+
+
+		public static VariableTerm ReduceVariable(VariableToken id, IOperandTerm p1, IOperandTerm p2, IOperandTerm p3)
+		{
+			IOperandTerm[] terms = null;
+			IOperandTerm op1 = p1;
+			IOperandTerm op2 = p2;
+			IOperandTerm op3 = p3;
+			//引数の推測
+			if (id.IsCharacterData)
+			{
+				if (id.IsArray2D)
+				{
+					if ((op1 == null) && (op2 == null) && (op3 == null))
+						return new VariableNoArgTerm(id);
+					if ((op1 == null) || (op2 == null) || (op3 == null))
+						throw new CodeEE("You cannot omit arguments for character two-dimensional array variable " + id.Name + "");
+					terms = new IOperandTerm[3];
+					terms[0] = op1;
+					terms[1] = op2;
+					terms[2] = op3;
+				}
+				else if (id.IsArray1D)
+				{
+					if (op3 != null)
+						throw new CodeEE("Character variable " + id.Name + " has too many arguments");
+					if ((op1 == null) && (op2 == null) && (op3 == null) && Config.SystemNoTarget)
+						return new VariableNoArgTerm(id);
+					if (op2 == null)
+					{
+						if (Config.SystemNoTarget)
+							throw new CodeEE("You cannot omit arguments for character two-dimensional array variable " + id.Name + " (Prohibited by current config)");
+						if (op1 == null)
+							op2 = ZeroTerm;
+						else
+							op2 = op1;
+						op1 = TARGET;
+					}
+					terms = new IOperandTerm[2];
+					terms[0] = op1;
+					terms[1] = op2;
+				}
+				else
+				{
+					if (op2 != null)
+						throw new CodeEE("Character variable " + id.Name + " has too many arguments");
+					if ((op1 == null) && (op2 == null) && (op3 == null) && Config.SystemNoTarget)
+						return new VariableNoArgTerm(id);
+					if (op1 == null)
+					{
+						if (Config.SystemNoTarget)
+							throw new CodeEE("Character variable " + id.Name + " cannot have omitted arguments (Prohibited by current config)");
+						op1 = TARGET;
+					}
+					terms = new IOperandTerm[1];
+					terms[0] = op1;
+				}
+			}
+			else if (id.IsArray3D)
+			{
+				if ((op1 == null) && (op2 == null) && (op3 == null))
+					return new VariableNoArgTerm(id);
+				if ((op1 == null) || (op2 == null) || (op3 == null))
+					throw new CodeEE("Three-dimensional array variable " + id.Name + " cannot have omitted arguments");
+				terms = new IOperandTerm[3];
+				terms[0] = op1;
+				terms[1] = op2;
+				terms[2] = op3;
+			}
+			else if (id.IsArray2D)
+			{
+				if ((op1 == null) && (op2 == null) && (op3 == null))
+					return new VariableNoArgTerm(id);
+				if ((op1 == null) || (op2 == null))
+					throw new CodeEE("Two-dimensional array variable " + id.Name + " cannot have omitted arguments");
+				if (op3 != null)
+					throw new CodeEE("Two-dimensional array " + id.Name + " has too many arguments");
+				terms = new IOperandTerm[2];
+				terms[0] = op1;
+				terms[1] = op2;
+			}
+			else if (id.IsArray1D)
+			{
+				if (op2 != null)
+					throw new CodeEE("One-dimensional array variable " + id.Name + " has too many arguments");
+                if (op1 == null)
+                {
+                    op1 = ZeroTerm;
+                    if (!Config.CompatiRAND && id.Code == VariableCode.RAND)
+                    {
+                        throw new CodeEE("RAND has an omitted argument");
+                    }
+                }
+                if (!Config.CompatiRAND && op1 is SingleTerm && id.Code == VariableCode.RAND)
+                {
+                    if (((SingleTerm)op1).Int == 0)
+                        throw new CodeEE("RAND has 0 as an argument");
+                }
+				terms = new IOperandTerm[1];
+				terms[0] = op1;
+			}
+			else if (op1 != null)
+			{
+				throw new CodeEE("Variable that is not an array " + id.Name + " is being called with an argument");
+			}
+			else
+				terms = new IOperandTerm[0];
+			for (int i = 0; i < terms.Length; i++)
+				if (terms[i].IsString)
+					terms[i] = new VariableStrArgTerm(id.Code, terms[i], i);
+			return new VariableTerm(id, terms);
+		}
+		//public static string ErrorMes = null;
+		//public static void ResetError()
+		//{
+		//    ErrorMes = null;
+		//}
+
+	}
+}

+ 56 - 0
NTERA/Game/GameData/Variable/VariableStrArgTerm.cs

@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameData.Variable
+{
+	
+	//変数の引数のうち文字列型のもの。
+	internal sealed class VariableStrArgTerm : IOperandTerm
+	{
+		public VariableStrArgTerm(VariableCode code, IOperandTerm strTerm, int index)
+			: base(typeof(Int64))
+		{
+			this.strTerm = strTerm;
+			parentCode = code;
+			this.index = index;
+		}
+		IOperandTerm strTerm;
+		readonly VariableCode parentCode;
+		readonly int index;
+		Dictionary<string, int> dic;
+		string errPos;
+		
+        public override Int64 GetIntValue(ExpressionMediator exm)
+		{
+			if (dic == null)
+				dic = exm.VEvaluator.Constant.GetKeywordDictionary(out errPos, parentCode, index);
+			string key = strTerm.GetStrValue(exm);
+
+					
+			if (key == "")
+				throw new CodeEE("キーワードを空には出来ません");
+			int i;
+			
+			if (!dic.TryGetValue(key, out i))
+			{
+				if (errPos == null)
+					throw new CodeEE("配列変数" + parentCode + "の要素を文字列で指定することはできません");
+				throw new CodeEE(errPos + "の中に\"" + key + "\"の定義がありません");
+			}
+			return i;
+        }
+		
+        public override IOperandTerm Restructure(ExpressionMediator exm, bool tryTranslate=false)
+        {
+			if (dic == null)
+				dic = exm.VEvaluator.Constant.GetKeywordDictionary(out errPos, parentCode, index);
+			strTerm = strTerm.Restructure(exm);
+			if (!(strTerm is SingleTerm))
+				return this;
+			return new SingleTerm(GetIntValue(exm));
+        }
+	}
+
+}

+ 441 - 0
NTERA/Game/GameData/Variable/VariableTerm.cs

@@ -0,0 +1,441 @@
+using System;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameData.Variable
+{
+
+	internal class VariableTerm : IOperandTerm
+	{
+		protected VariableTerm(VariableToken token) : base(token.VariableType) { }
+		public VariableTerm(VariableToken token, IOperandTerm[] args)
+			: base(token.VariableType)
+		{
+			Identifier = token;
+			arguments = args;
+			transporter = new Int64[arguments.Length];
+
+			allArgIsConst = false;
+			for (int i = 0; i < arguments.Length; i++)
+			{
+				if (!(arguments[i] is SingleTerm))
+					return;
+				transporter[i] = ((SingleTerm)arguments[i]).Int;
+			}
+			allArgIsConst = true;
+		}
+		public VariableToken Identifier;
+		private readonly IOperandTerm[] arguments;
+		protected Int64[] transporter;
+		protected bool allArgIsConst;
+
+		public Int64 GetElementInt(int i, ExpressionMediator exm)
+		{
+			if (allArgIsConst)
+				return transporter[i];
+			return arguments[i].GetIntValue(exm);
+		}
+
+		public bool isAllConst => allArgIsConst;
+		public int getEl1forArg => (int)transporter[0];
+
+		public override Int64 GetIntValue(ExpressionMediator exm)
+		{
+			try
+			{
+				if (!allArgIsConst)
+					for (int i = 0; i < arguments.Length; i++)
+						transporter[i] = arguments[i].GetIntValue(exm);
+				return Identifier.GetIntValue(exm, transporter);
+			}
+			catch (Exception e)
+			{
+				if ((e is IndexOutOfRangeException) || (e is ArgumentOutOfRangeException) || (e is OverflowException))
+					Identifier.CheckElement(transporter);
+				throw;
+			}
+		}
+		//, bool tl = false
+		public override string GetStrValue(ExpressionMediator exm, bool translate=false)
+		{
+			try
+			{
+				if (!allArgIsConst)
+					for (int i = 0; i < arguments.Length; i++)
+						transporter[i] = arguments[i].GetIntValue(exm);
+				string ret = Identifier.GetStrValue(exm, transporter, translate);
+				if (ret == null)
+					return "";
+				return ret;
+			}
+			catch (Exception e)
+			{
+				if ((e is IndexOutOfRangeException) || (e is ArgumentOutOfRangeException) || (e is OverflowException))
+					Identifier.CheckElement(transporter);
+				throw;
+			}
+		}
+
+		public virtual void SetValue(Int64 value, ExpressionMediator exm)
+		{
+			try
+			{
+				if (!allArgIsConst)
+					for (int i = 0; i < arguments.Length; i++)
+						transporter[i] = arguments[i].GetIntValue(exm);
+				Identifier.SetValue(value, transporter);
+			}
+			catch (Exception e)
+			{
+				if ((e is IndexOutOfRangeException) || (e is ArgumentOutOfRangeException) || (e is OverflowException))
+					Identifier.CheckElement(transporter);
+				throw;
+			}
+		}
+		public virtual void SetValue(string value, ExpressionMediator exm)
+		{
+			try
+			{
+				if (!allArgIsConst)
+					for (int i = 0; i < arguments.Length; i++)
+						transporter[i] = arguments[i].GetIntValue(exm);
+				Identifier.SetValue(value, transporter);
+			}
+			catch (Exception e)
+			{
+				if ((e is IndexOutOfRangeException) || (e is ArgumentOutOfRangeException) || (e is OverflowException))
+					Identifier.CheckElement(transporter);
+				throw e;
+			}
+		}
+
+		public virtual void SetValue(Int64[] array, ExpressionMediator exm)
+		{
+			try
+			{
+				if (!allArgIsConst)
+					for (int i = 0; i < arguments.Length; i++)
+						transporter[i] = arguments[i].GetIntValue(exm);
+				Identifier.SetValue(array, transporter);
+			}
+			catch (Exception e)
+			{
+				if ((e is IndexOutOfRangeException) || (e is ArgumentOutOfRangeException) || (e is OverflowException))
+				{
+					Identifier.CheckElement(transporter);
+					throw new CodeEE("配列変数" + Identifier.Name + "の要素数を超えて代入しようとしました");
+				}
+				throw;
+			}
+		}
+		public virtual void SetValue(string[] array, ExpressionMediator exm)
+		{
+			try
+			{
+				if (!allArgIsConst)
+					for (int i = 0; i < arguments.Length; i++)
+						transporter[i] = arguments[i].GetIntValue(exm);
+				Identifier.SetValue(array, transporter);
+			}
+			catch (Exception e)
+			{
+				if ((e is IndexOutOfRangeException) || (e is ArgumentOutOfRangeException) || (e is OverflowException))
+				{
+					Identifier.CheckElement(transporter);
+					throw new CodeEE("配列変数" + Identifier.Name + "の要素数を超えて代入しようとしました");
+				}
+				throw;
+			}
+		}
+
+		public virtual Int64 PlusValue(Int64 value, ExpressionMediator exm)
+		{
+			try
+			{
+				if (!allArgIsConst)
+					for (int i = 0; i < arguments.Length; i++)
+						transporter[i] = arguments[i].GetIntValue(exm);
+				return Identifier.PlusValue(value, transporter);
+			}
+			catch (Exception e)
+			{
+				if ((e is IndexOutOfRangeException) || (e is ArgumentOutOfRangeException) || (e is OverflowException))
+					Identifier.CheckElement(transporter);
+				throw;
+			}
+		}
+		public override SingleTerm GetValue(ExpressionMediator exm, bool tryTranslate =false)
+		{
+			if (Identifier.VariableType == typeof(Int64))
+				return new SingleTerm(GetIntValue(exm));
+			return new SingleTerm(GetStrValue(exm, tryTranslate));
+		}
+		public virtual void SetValue(SingleTerm value, ExpressionMediator exm)
+		{
+			if (Identifier.VariableType == typeof(Int64))
+				SetValue(value.Int, exm);
+			else
+				SetValue(value.Str, exm);
+		}
+		public virtual void SetValue(IOperandTerm value, ExpressionMediator exm)
+		{
+			if (Identifier.VariableType == typeof(Int64))
+				SetValue(value.GetIntValue(exm), exm);
+			else
+				SetValue(value.GetStrValue(exm), exm);
+		}
+		public Int32 GetLength()
+		{
+			return Identifier.GetLength();
+		}
+		public Int32 GetLength(int dimension)
+		{
+			return Identifier.GetLength(dimension);
+		}
+		public Int32 GetLastLength()
+		{
+			if (Identifier.IsArray1D)
+				return Identifier.GetLength();
+			if (Identifier.IsArray2D)
+				return Identifier.GetLength(1);
+			if (Identifier.IsArray3D)
+				return Identifier.GetLength(2);
+			return 0;
+		}
+
+		public virtual FixedVariableTerm GetFixedVariableTerm(ExpressionMediator exm)
+		{
+			if (!allArgIsConst)
+				for (int i = 0; i < arguments.Length; i++)
+					transporter[i] = arguments[i].GetIntValue(exm);
+			FixedVariableTerm fp = new FixedVariableTerm(Identifier);
+			if (transporter.Length >= 1)
+				fp.Index1 = transporter[0];
+			if (transporter.Length >= 2)
+				fp.Index2 = transporter[1];
+			if (transporter.Length >= 3)
+				fp.Index3 = transporter[2];
+			return fp;
+		}
+
+		public override IOperandTerm Restructure(ExpressionMediator exm, bool tryTranslate=false)
+		{
+			bool[] canCheck = new bool[arguments.Length];
+			allArgIsConst = true;
+			for (int i = 0; i < arguments.Length; i++)
+			{
+				arguments[i] = arguments[i].Restructure(exm);
+				if (!(arguments[i] is SingleTerm))
+				{
+					allArgIsConst = false;
+					canCheck[i] = false;
+				}
+				else
+				{
+					//キャラクターデータの第1引数はこの時点でチェックしても意味がないのと
+					//ARG系は限界超えてても必要な数に拡張されるのでチェックしなくていい
+					if ((i == 0 && Identifier.IsCharacterData) || Identifier.Name == "ARG" || Identifier.Name == "ARGS")
+						canCheck[i] = false;
+					else
+						canCheck[i] = true;
+					//if (allArgIsConst)
+					//チェックのために値が必要
+					transporter[i] = arguments[i].GetIntValue(exm);
+				}
+			}
+			if (!Identifier.IsReference)
+				Identifier.CheckElement(transporter, canCheck);
+			if ((Identifier.CanRestructure) && (allArgIsConst))
+				return GetValue(exm, tryTranslate);//We pass the bool by here REEEEEEEEEEEEEEEEE
+			if (allArgIsConst)
+				return new FixedVariableTerm(Identifier, transporter);
+			return this;
+		}
+
+        //以下添え字解析用の追加関数
+        public bool checkSameTerm(VariableTerm term)
+        {
+            //添え字が全部定数があることがこの関数の前提(そもそもそうでないと使い道がない)
+            if (!allArgIsConst)
+                return false;
+            if (Identifier.Name != term.Identifier.Name)
+                return false;
+	        for (int i = 0; i < transporter.Length; i++)
+	        {
+		        if (transporter[i] != term.transporter[i])
+			        return false;
+	        }
+	        return true;
+        }
+
+        public string GetFullString()
+        {
+            //添え字が全部定数があることがこの関数の前提(IOperandTermから変数名を取れないため)
+            if (!allArgIsConst)
+                return "";
+            if (Identifier.IsArray1D)
+                return Identifier.Name + ":" + transporter[0];
+	        if (Identifier.IsArray2D)
+		        return Identifier.Name + ":" + transporter[0] + ":" + transporter[1];
+	        if (Identifier.IsArray3D)
+		        return Identifier.Name + ":" + transporter[0] + ":" + transporter[1] + ":" + transporter[2];
+	        return Identifier.Name;
+        }
+	}
+
+	
+    internal sealed class FixedVariableTerm : VariableTerm
+    {
+		public FixedVariableTerm(VariableToken token)
+			: base(token)
+		{
+			Identifier = token;
+			transporter = new Int64[3];
+			allArgIsConst = true;
+		}
+		public FixedVariableTerm(VariableToken token, Int64[] args)
+			: base(token)
+		{
+			allArgIsConst = true;
+			Identifier = token;
+			transporter = new Int64[3];
+			for(int i = 0;i< args.Length;i++)
+				transporter[i] = args[i];
+		}
+		public Int64 Index1{get => transporter[0];
+			set{transporter[0] = value;}}
+		public Int64 Index2{get => transporter[1];
+			set{transporter[1] = value;}}
+        public Int64 Index3{get => transporter[2];
+	        set{transporter[2] = value;}}
+        
+		
+        public override Int64 GetIntValue(ExpressionMediator exm)
+        {
+			try
+			{
+				return Identifier.GetIntValue(exm, transporter);
+			}
+			catch(Exception e)
+			{
+				if ((e is IndexOutOfRangeException) || (e is ArgumentOutOfRangeException) || (e is OverflowException))
+					Identifier.CheckElement(transporter);
+				throw;
+			}
+        }
+		//, bool tl = false
+        public override string GetStrValue(ExpressionMediator exm, bool translate=false)
+        {
+			try
+			{
+				string ret = Identifier.GetStrValue(exm, transporter, translate);
+				if (ret == null)
+					return "";
+				return ret;
+			}
+			catch(Exception e)
+			{
+				if ((e is IndexOutOfRangeException) || (e is ArgumentOutOfRangeException) || (e is OverflowException))
+					Identifier.CheckElement(transporter);
+				throw;
+			}
+        }
+
+		public override void SetValue(Int64 value, ExpressionMediator exm)
+        {
+			try
+			{
+				Identifier.SetValue(value, transporter);
+			}
+			catch(Exception e)
+			{
+				if ((e is IndexOutOfRangeException) || (e is ArgumentOutOfRangeException) || (e is OverflowException))
+					Identifier.CheckElement(transporter);
+				throw;
+			}
+        }
+		public override void SetValue(string value, ExpressionMediator exm)
+        {
+			try
+			{
+				Identifier.SetValue(value, transporter);
+			}
+			catch(Exception e)
+			{
+				if ((e is IndexOutOfRangeException) || (e is ArgumentOutOfRangeException) || (e is OverflowException))
+					Identifier.CheckElement(transporter);
+				throw;
+			}
+        }
+
+		public override Int64 PlusValue(Int64 value, ExpressionMediator exm)
+        {
+			try
+			{
+				return Identifier.PlusValue(value, transporter);
+			}
+			catch(Exception e)
+			{
+				if ((e is IndexOutOfRangeException) || (e is ArgumentOutOfRangeException) || (e is OverflowException))
+					Identifier.CheckElement(transporter);
+				throw;
+			}
+        }
+        
+        public override IOperandTerm Restructure(ExpressionMediator exm, bool tryTranslate=false)
+        {
+			if (Identifier.CanRestructure)
+				return GetValue(exm);
+			return this;
+        }
+        
+		public void IsArrayRangeValid(Int64 index1, Int64 index2, string funcName, Int64 i1, Int64 i2)
+		{
+			Identifier.IsArrayRangeValid(transporter, index1, index2, funcName, i1, i2);
+		}
+    }
+
+
+	/// <summary>
+	/// 引数がない変数。値を参照、代入できない
+	/// </summary>
+	internal sealed class VariableNoArgTerm : VariableTerm
+	{
+		public VariableNoArgTerm(VariableToken token)
+			: base(token)
+		{
+			Identifier = token;
+			allArgIsConst = true;
+		}
+		public override Int64 GetIntValue(ExpressionMediator exm)
+		{ throw new CodeEE("変数" + Identifier.Name + "に必要な引数が不足しています"); }
+		public override string GetStrValue(ExpressionMediator exm, bool translate=false)
+		{ throw new CodeEE("変数" + Identifier.Name + "に必要な引数が不足しています"); }
+		public override void SetValue(Int64 value, ExpressionMediator exm)
+		{ throw new CodeEE("変数" + Identifier.Name + "に必要な引数が不足しています"); }
+		public override void SetValue(string value, ExpressionMediator exm)
+		{ throw new CodeEE("変数" + Identifier.Name + "に必要な引数が不足しています"); }
+		public override void SetValue(Int64[] array, ExpressionMediator exm)
+		{ throw new CodeEE("変数" + Identifier.Name + "に必要な引数が不足しています"); }
+		public override void SetValue(string[] array, ExpressionMediator exm)
+		{ throw new CodeEE("変数" + Identifier.Name + "に必要な引数が不足しています"); }
+		public override Int64 PlusValue(Int64 value, ExpressionMediator exm)
+		{ throw new CodeEE("変数" + Identifier.Name + "に必要な引数が不足しています"); }
+		public override SingleTerm GetValue(ExpressionMediator exm, bool tryTranslate =false)
+		{ throw new CodeEE("変数" + Identifier.Name + "に必要な引数が不足しています"); }
+		public override void SetValue(SingleTerm value, ExpressionMediator exm)
+		{ throw new CodeEE("変数" + Identifier.Name + "に必要な引数が不足しています"); }
+		public override void SetValue(IOperandTerm value, ExpressionMediator exm)
+		{ throw new CodeEE("変数" + Identifier.Name + "に必要な引数が不足しています"); }
+		public override FixedVariableTerm GetFixedVariableTerm(ExpressionMediator exm)
+		{ throw new CodeEE("変数" + Identifier.Name + "に必要な引数が不足しています"); }
+
+		public override IOperandTerm Restructure(ExpressionMediator exm, bool tryTranslate=false)
+		{
+			return this;
+		}
+
+	
+
+	}
+}

+ 2956 - 0
NTERA/Game/GameData/Variable/VariableToken.cs

@@ -0,0 +1,2956 @@
+using System;
+using System.Collections.Generic;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.GameProc;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameData.Variable
+{
+	//IndexOutOfRangeException, ArgumentOutOfRangeExceptionを投げることがある。VariableTermの方で処理すること。
+	//引数は整数しか受け付けない。*.csvを利用した置換はVariableTermの方で処理すること
+	internal abstract class VariableToken
+	{
+		protected VariableToken(VariableCode varCode, VariableData varData)
+		{
+			Code = varCode;
+			VariableType = ((varCode & VariableCode.__INTEGER__) == VariableCode.__INTEGER__) ? typeof(Int64) : typeof(string);
+			VarCodeInt = (int)(varCode & VariableCode.__LOWERCASE__);
+			varName = varCode.ToString();
+			this.varData = varData;
+			IsForbid = false;
+			IsPrivate = false;
+			IsReference = false;
+			Dimension = 0;
+			IsGlobal = (Code == VariableCode.GLOBAL) || (Code == VariableCode.GLOBALS);
+			if ((Code & VariableCode.__ARRAY_1D__) == VariableCode.__ARRAY_1D__)
+				Dimension = 1;
+			if ((Code & VariableCode.__ARRAY_2D__) == VariableCode.__ARRAY_2D__)
+				Dimension = 2;
+			if ((Code & VariableCode.__ARRAY_3D__) == VariableCode.__ARRAY_3D__)
+				Dimension = 3;
+
+
+			IsSavedata = false;
+			if ((Code == VariableCode.GLOBAL) || (Code == VariableCode.GLOBALS))
+				IsSavedata = true;
+			else if ((Code & VariableCode.__SAVE_EXTENDED__) == VariableCode.__SAVE_EXTENDED__)
+			{
+				IsSavedata = true;
+			}
+			else if (((Code & VariableCode.__EXTENDED__) != VariableCode.__EXTENDED__)
+				&& ((Code & VariableCode.__CALC__) != VariableCode.__CALC__)
+				&& ((Code & VariableCode.__UNCHANGEABLE__) != VariableCode.__UNCHANGEABLE__)
+				&& ((Code & VariableCode.__LOCAL__) != VariableCode.__LOCAL__)
+				&& (!varName.StartsWith("NOTUSE_")))
+			{
+				VariableCode flag = Code & (VariableCode.__ARRAY_1D__ | VariableCode.__ARRAY_2D__ | VariableCode.__ARRAY_3D__ | VariableCode.__STRING__ | VariableCode.__INTEGER__ | VariableCode.__CHARACTER_DATA__);
+				switch (flag)
+				{
+					case VariableCode.__CHARACTER_DATA__ | VariableCode.__INTEGER__:
+						if (VarCodeInt < (int)VariableCode.__COUNT_SAVE_CHARACTER_INTEGER__)
+							IsSavedata = true;
+						break;
+					case VariableCode.__CHARACTER_DATA__ | VariableCode.__STRING__:
+						if (VarCodeInt < (int)VariableCode.__COUNT_SAVE_CHARACTER_STRING__)
+							IsSavedata = true;
+						break;
+					case VariableCode.__CHARACTER_DATA__ | VariableCode.__INTEGER__ | VariableCode.__ARRAY_1D__:
+						if (VarCodeInt < (int)VariableCode.__COUNT_SAVE_CHARACTER_INTEGER_ARRAY__)
+							IsSavedata = true;
+						break;
+					case VariableCode.__CHARACTER_DATA__ | VariableCode.__STRING__ | VariableCode.__ARRAY_1D__:
+						if (VarCodeInt < (int)VariableCode.__COUNT_SAVE_CHARACTER_STRING_ARRAY__)
+							IsSavedata = true;
+						break;
+					case VariableCode.__INTEGER__:
+						if (VarCodeInt < (int)VariableCode.__COUNT_SAVE_INTEGER__)
+							IsSavedata = true;
+						break;
+					case VariableCode.__STRING__:
+						if (VarCodeInt < (int)VariableCode.__COUNT_SAVE_STRING__)
+							IsSavedata = true;
+						break;
+					case VariableCode.__INTEGER__ | VariableCode.__ARRAY_1D__:
+						if (VarCodeInt < (int)VariableCode.__COUNT_SAVE_INTEGER_ARRAY__)
+							IsSavedata = true;
+						break;
+					case VariableCode.__STRING__ | VariableCode.__ARRAY_1D__:
+						if (VarCodeInt < (int)VariableCode.__COUNT_SAVE_STRING_ARRAY__)
+							IsSavedata = true;
+						break;
+				}
+			}
+		}
+
+		public readonly VariableCode Code;
+		public readonly int VarCodeInt;
+		protected readonly VariableData varData;
+		protected string varName;
+		public Type VariableType { get; protected set; }
+		public bool CanRestructure { get; protected set; }
+		public string Name => varName;
+
+
+		//CodeEEにしているけど実際はExeEEかもしれない
+		public virtual Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+		{ throw new CodeEE("整数型でない変数" + varName + "を整数型として呼び出しました"); }
+		public virtual string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+		{ throw new CodeEE("文字列型でない変数" + varName + "を文字列型として呼び出しました"); }
+		public virtual void SetValue(Int64 value, Int64[] arguments)
+		{ throw new CodeEE("整数型でない変数" + varName + "を整数型として呼び出しました"); }
+		public virtual void SetValue(string value, Int64[] arguments)
+		{ throw new CodeEE("文字列型でない変数" + varName + "を文字列型として呼び出しました"); }
+		public virtual void SetValue(Int64[] values, Int64[] arguments)
+		{ throw new CodeEE("整数型配列でない変数" + varName + "を整数型配列として呼び出しました"); }
+		public virtual void SetValue(string[] values, Int64[] arguments)
+		{ throw new CodeEE("文字列型配列でない変数" + varName + "を文字列型配列として呼び出しました"); }
+		public virtual void SetValueAll(Int64 value, int start, int end, int charaPos)
+		{ throw new CodeEE("整数型配列でない変数" + varName + "を整数型配列として呼び出しました"); }
+		public virtual void SetValueAll(string value, int start, int end, int charaPos)
+		{ throw new CodeEE("文字列型配列でない変数" + varName + "を文字列型配列として呼び出しました"); }
+		public virtual Int64 PlusValue(Int64 value, Int64[] arguments)
+		{ throw new CodeEE("整数型でない変数" + varName + "を整数型として呼び出しました"); }
+		public virtual Int32 GetLength()
+		{ throw new CodeEE("配列型でない変数" + varName + "の長さを取得しようとしました"); }
+		public virtual Int32 GetLength(int dimension)
+		{ throw new CodeEE("配列型でない変数" + varName + "の長さを取得しようとしました"); }
+		public virtual object GetArray()
+		{
+			if (IsCharacterData)
+				throw new CodeEE("キャラクタ変数" + varName + "を非キャラ変数として呼び出しました");
+			throw new CodeEE("配列型でない変数" + varName + "の配列を取得しようとしました");
+		}
+		public virtual object GetArrayChara(int charano)
+		{
+			if (!IsCharacterData)
+				throw new CodeEE("非キャラクタ変数" + varName + "をキャラ変数として呼び出しました");
+			throw new CodeEE("配列型でない変数" + varName + "の配列を取得しようとしました");
+		}
+
+		public void throwOutOfRangeException(Int64[] arguments, Exception e)
+		{
+			CheckElement(arguments, new[] { true, true, true });
+			throw e;
+		}
+		public virtual void CheckElement(Int64[] arguments, bool[] doCheck) { }
+		public void CheckElement(Int64[] arguments)
+		{
+			CheckElement(arguments, new[] { true, true, true });
+		}
+		public virtual void IsArrayRangeValid(Int64[] arguments, Int64 index1, Int64 index2, string funcName, Int64 i1, Int64 i2)
+		{
+			CheckElement(arguments, new[] { true, true, true });
+		}
+
+		public int CodeInt => VarCodeInt;
+
+		public VariableCode CodeFlag => Code & VariableCode.__UPPERCASE__;
+
+		public bool IsNull => Code == VariableCode.__NULL__;
+
+		public bool IsCharacterData => ((Code & VariableCode.__CHARACTER_DATA__) == VariableCode.__CHARACTER_DATA__);
+
+		public bool IsInteger => ((Code & VariableCode.__INTEGER__) == VariableCode.__INTEGER__);
+
+		public bool IsString => ((Code & VariableCode.__STRING__) == VariableCode.__STRING__);
+
+		public bool IsArray1D => ((Code & VariableCode.__ARRAY_1D__) == VariableCode.__ARRAY_1D__);
+
+		public bool IsArray2D => ((Code & VariableCode.__ARRAY_2D__) == VariableCode.__ARRAY_2D__);
+
+		public bool IsArray3D => ((Code & VariableCode.__ARRAY_3D__) == VariableCode.__ARRAY_3D__);
+
+		/// <summary>
+		/// 1810alpha007 諸事情によりReadOnlyからIsConstに改名。
+		/// </summary>
+		public virtual bool IsConst => ((Code & VariableCode.__UNCHANGEABLE__) == VariableCode.__UNCHANGEABLE__);
+
+		public bool IsCalc => ((Code & VariableCode.__CALC__) == VariableCode.__CALC__);
+
+		public bool IsLocal => ((Code & VariableCode.__LOCAL__) == VariableCode.__LOCAL__);
+
+		public bool CanForbid => ((Code & VariableCode.__CAN_FORBID__) == VariableCode.__CAN_FORBID__);
+		public bool IsForbid { get; protected set; }
+		public bool IsPrivate { get; protected set; }
+		public bool IsGlobal { get; protected set; }
+		public bool IsSavedata { get; protected set; }
+		public bool IsReference { get; protected set; }
+		public int Dimension { get; protected set; }
+
+	}
+
+	internal abstract class CharaVariableToken : VariableToken
+	{
+		protected CharaVariableToken(VariableCode varCode, VariableData varData)
+			: base(varCode, varData)
+		{
+			sizes = CharacterData.CharacterVarLength(varCode, varData.Constant);
+			if (sizes != null)
+			{
+				totalSize = 1;
+				for (int i = 0; i < sizes.Length; i++)
+					totalSize *= sizes[i];
+				IsForbid = totalSize == 0;
+			}
+			IsPrivate = false;
+			CanRestructure = false;
+		}
+		protected int[] sizes;
+		protected int totalSize;
+		public override Int32 GetLength()
+		{
+			if (sizes.Length == 1)
+				return sizes[0];
+			if (sizes.Length == 0)
+				throw new CodeEE("非配列型のキャラ変数" + varName + "の長さを取得しようとしました");
+			throw new CodeEE(Dimension + "次元配列型のキャラ変数" + varName + "の長さを次元を指定せずに取得しようとしました");
+		}
+		public override Int32 GetLength(int dimension)
+		{
+			if (sizes.Length == 0)
+				throw new CodeEE("非配列型のキャラ変数" + varName + "の長さを取得しようとしました");
+			if (dimension < sizes.Length)
+				return sizes[dimension];
+			throw new CodeEE("配列型変数のキャラ変数" + varName + "の存在しない次元の長さを取得しようとしました");
+		}
+		public override void CheckElement(Int64[] arguments, bool[] doCheck)
+		{
+			if (doCheck[0] && ((arguments[0] < 0) || (arguments[0] >= varData.CharacterList.Count)))
+				throw new CodeEE("Character array variable " + varName + " at the first argument (" + arguments[0] + ") is out of range of the character registration number");
+			if (doCheck.Length > 1 && sizes.Length > 0 && doCheck[1] && ((arguments[1] < 0) || (arguments[1] >= sizes[0])))
+				throw new CodeEE("Character array variable " + varName + " at the second argument (" + arguments[1] + ") is out of range of the array");
+			if (doCheck.Length > 2 && sizes.Length > 1 && doCheck[2] && ((arguments[2] < 0) || (arguments[2] >= sizes[1])))
+				throw new CodeEE("Character array variable " + varName + " at the third argument (" + arguments[2] + ") is out of range of the array");
+		}
+
+		public override void IsArrayRangeValid(Int64[] arguments, Int64 index1, Int64 index2, string funcName, Int64 i1, Int64 i2)
+		{
+			CheckElement(arguments);
+			CharacterData chara = varData.CharacterList[(int)arguments[0]];
+			if ((index1 < 0) || (index1 > sizes[0]))
+				throw new CodeEE(funcName + "命令の第" + i1 + "引数(" + index1 + ")は配列" + varName + "の範囲外です");
+			if ((index2 < 0) || (index2 > sizes[0]))
+				throw new CodeEE(funcName + "命令の第" + i2 + "引数(" + index2 + ")は配列" + varName + "の範囲外です");
+		}
+	}
+
+	internal abstract class UserDefinedVariableToken : VariableToken
+	{
+		protected UserDefinedVariableToken(VariableCode varCode, UserDefinedVariableData data)
+			: base(varCode, null)
+		{
+			varName = data.Name;
+			IsPrivate = data.Private;
+			isConst = data.Const;
+			sizes = data.Lengths;
+			IsGlobal = data.Global;
+			IsSavedata = data.Save;
+			//Dimension = sizes.Length;
+			totalSize = 1;
+			for (int i = 0; i < sizes.Length; i++)
+				totalSize *= sizes[i];
+			IsForbid = totalSize == 0;
+			CanRestructure = isConst;
+		}
+
+		public abstract void SetDefault();
+		protected bool isConst;
+		protected int[] sizes;
+		protected int totalSize;
+		//public bool IsGlobal { get; protected set; }
+		//public bool IsSavedata { get; protected set; }
+		public override bool IsConst => isConst;
+
+		public override Int32 GetLength()
+		{
+			if (Dimension == 1)
+				return sizes[0];
+			throw new CodeEE(Dimension + "次元配列型変数" + varName + "の長さを取得しようとしました");
+		}
+
+		public override Int32 GetLength(int dimension)
+		{
+			if (dimension < Dimension)
+				return sizes[dimension];
+			throw new CodeEE("配列型変数" + varName + "の存在しない次元の長さを取得しようとしました");
+		}
+		public override void CheckElement(Int64[] arguments, bool[] doCheck)
+		{
+			//if (array == null)
+			//	throw new ExeEE("プライベート変数" + varName + "の配列が用意されていない");
+
+			if (doCheck[0] && ((arguments[0] < 0) || (arguments[0] >= sizes[0])))
+				throw new CodeEE("配列型変数" + varName + "の第1引数(" + arguments[0] + ")は配列の範囲外です");
+			if (sizes.Length >= 2 && ((arguments[1] < 0) || (arguments[1] >= sizes[1])))
+				throw new CodeEE("配列型変数" + varName + "の第2引数(" + arguments[1] + ")は配列の範囲外です");
+			if (sizes.Length >= 3 && ((arguments[2] < 0) || (arguments[2] >= sizes[2])))
+				throw new CodeEE("配列型変数" + varName + "の第3引数(" + arguments[2] + ")は配列の範囲外です");
+		}
+		public override void IsArrayRangeValid(Int64[] arguments, Int64 index1, Int64 index2, string funcName, Int64 i1, Int64 i2)
+		{
+			CheckElement(arguments);
+			if ((index1 < 0) || (index1 > sizes[Dimension - 1]))
+				throw new CodeEE(funcName + "命令の第" + i1 + "引数(" + index1 + ")は配列" + varName + "の範囲外です");
+			if ((index2 < 0) || (index2 > sizes[Dimension - 1]))
+				throw new CodeEE(funcName + "命令の第" + i2 + "引数(" + index2 + ")は配列" + varName + "の範囲外です");
+		}
+		public abstract void In();
+		public abstract void Out();
+		public bool IsStatic { get; protected set; }
+	}
+
+	internal abstract class UserDefinedCharaVariableToken : CharaVariableToken
+	{
+		protected UserDefinedCharaVariableToken(VariableCode varCode, UserDefinedVariableData data, VariableData varData, int arrayIndex)
+			: base(varCode, varData)
+		{
+			ArrayIndex = arrayIndex;
+			DimData = data;
+			varName = data.Name;
+			sizes = data.Lengths;
+			IsGlobal = data.Global;
+			IsSavedata = data.Save;
+			//Dimension = sizes.Length;
+			totalSize = 1;
+			for (int i = 0; i < sizes.Length; i++)
+				totalSize *= sizes[i];
+			IsForbid = totalSize == 0;
+		}
+		public readonly UserDefinedVariableData DimData;
+		public readonly int ArrayIndex;
+		public override object GetArrayChara(int charano)
+		{
+			return varData.CharacterList[charano].UserDefCVarDataList[ArrayIndex];
+		}
+
+	}
+
+	//1808beta009 廃止 UserDefinedVariableTokenで一括して扱う
+	//internal abstract class PrivateVariableToken : UserDefinedVariableToken
+	//{
+	//    protected PrivateVariableToken(VariableCode varCode, UserDefinedVariableData data)
+	//        : base(varCode, data)
+	//    {
+	//        IsPrivate = true;
+	//    }
+	//}
+
+	/// <summary>
+	/// 1808beta009 追加
+	/// 参照型。public もあるよ
+	/// </summary>
+	internal abstract class ReferenceToken : UserDefinedVariableToken
+	{
+		protected ReferenceToken(VariableCode varCode, UserDefinedVariableData data)
+			: base(varCode, data)
+		{
+			CanRestructure = false;
+			IsStatic = !data.Private;
+			IsReference = true;
+			arrayList = new List<Array>();
+			IsForbid = false;
+		}
+		protected List<Array> arrayList;
+		protected Array array;
+
+		public override void SetDefault()
+		{//Defaultのセットは参照元がやるべき
+		}
+		public override Int32 GetLength()
+		{
+			if (array == null)
+				throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+			if (Dimension != 1)
+				throw new CodeEE(Dimension + "次元配列型変数" + varName + "の長さを取得しようとしました");
+			return array.Length;
+		}
+
+		public override Int32 GetLength(int dimension)
+		{
+			if (array == null)
+				throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+			if (dimension < Dimension)
+				return array.GetLength(dimension);
+			throw new CodeEE("配列型変数" + varName + "の存在しない次元の長さを取得しようとしました");
+		}
+		public override void CheckElement(Int64[] arguments, bool[] doCheck)
+		{
+			if (array == null)
+				throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+			if (doCheck[0] && ((arguments[0] < 0) || (arguments[0] >= array.GetLength(0))))
+				throw new CodeEE("配列型変数" + varName + "の第1引数(" + arguments[0] + ")は配列の範囲外です");
+			if (Dimension >= 2 && ((arguments[1] < 0) || (arguments[1] >= array.GetLength(1))))
+				throw new CodeEE("配列型変数" + varName + "の第2引数(" + arguments[1] + ")は配列の範囲外です");
+			if (Dimension >= 3 && ((arguments[2] < 0) || (arguments[2] >= array.GetLength(2))))
+				throw new CodeEE("配列型変数" + varName + "の第3引数(" + arguments[2] + ")は配列の範囲外です");
+		}
+		public override void IsArrayRangeValid(Int64[] arguments, Int64 index1, Int64 index2, string funcName, Int64 i1, Int64 i2)
+		{
+			CheckElement(arguments);
+			if ((index1 < 0) || (index1 > array.GetLength(Dimension - 1)))
+				throw new CodeEE(funcName + "命令の第" + i1 + "引数(" + index1 + ")は配列" + varName + "の範囲外です");
+			if ((index2 < 0) || (index2 > array.GetLength(Dimension - 1)))
+				throw new CodeEE(funcName + "命令の第" + i2 + "引数(" + index2 + ")は配列" + varName + "の範囲外です");
+		}
+
+		int counter;
+		public override void In()
+		{
+			if (counter > 0)
+				arrayList.Add(array);
+			counter++;
+			array = null;
+		}
+
+		public override void Out()
+		{
+			//arrayList.RemoveAt(arrayList.Count - 1);
+			if (arrayList.Count > 0)
+			{
+				array = arrayList[arrayList.Count - 1];
+				arrayList.RemoveAt(arrayList.Count - 1);
+			}
+			else
+				array = null;
+			counter--;
+		}
+		public override object GetArray()
+		{
+			if (array == null)
+				throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+			return array;
+		}
+
+		public void SetRef(Array refArray)
+		{
+			array = refArray;
+		}
+
+		/// <summary>
+		/// 型が一致するかどうか(参照可能かどうか)
+		/// </summary>
+		/// <param name="rother"></param>
+		/// <returns></returns>
+		public bool MatchType(VariableToken rother, bool allowChara, out string errMes)
+		{
+			errMes = "";
+			if (rother == null)
+			{ errMes = "参照先変数は省略できません"; return false; }
+			if (rother.IsCalc)
+			{ errMes = "疑似変数は参照できません"; return false; }
+			//TODO constの参照
+			//if (rother.IsConst != this.isConst)
+			if (rother.IsConst)
+			{ errMes = "定数は参照できません"; return false; }
+			//1812 ローカル参照の条件変更
+			//ローカルかつDYNAMICなREFはローカル参照できる
+			if ((!IsPrivate) && (rother.IsPrivate || rother.IsLocal))
+			{ errMes = "広域の参照変数はローカル変数を参照できません"; return false; }
+			////1810beta002 ローカル参照禁止
+			//if ((!rother.IsReference) && (rother.IsPrivate || rother.IsLocal))
+			//{ errMes = "ローカル変数は参照できません"; return false; }
+			if (rother.IsCharacterData && !allowChara)
+			{ errMes = "キャラ変数は参照できません"; return false; }
+			if (IsInteger != rother.IsInteger)
+			{ errMes = "型が異なる変数は参照できません"; return false; }
+			if (Dimension != rother.Dimension)
+			{ errMes = "次元数が異なる変数は参照できません"; return false; }
+			return true;
+		}
+	}
+
+	internal abstract class LocalVariableToken : VariableToken
+	{
+		public LocalVariableToken(VariableCode varCode, VariableData varData, string subId, int size)
+			: base(varCode, varData)
+		{
+			CanRestructure = false;
+			subID = subId;
+			this.size = size;
+		}
+		public abstract void SetDefault();
+		public abstract void resize(int newSize);
+		protected string subID;
+		protected int size;
+		public override Int32 GetLength()
+		{
+			return size;
+		}
+		public override Int32 GetLength(int dimension)
+		{
+			if (dimension == 0)
+				return size;
+			throw new CodeEE("配列型変数" + varName + "の存在しない次元の長さを取得しようとしました");
+		}
+		public override void CheckElement(Int64[] arguments, bool[] doCheck)
+		{
+			//if (array == null)
+			//	throw new ExeEE("プライベート変数" + varName + "の配列が用意されていない");
+			if (doCheck[0] && ((arguments[0] < 0) || (arguments[0] >= size)))
+				throw new CodeEE("配列変数" + varName + "の第1引数(" + arguments[0] + ")は配列の範囲外です");
+		}
+		public override void IsArrayRangeValid(Int64[] arguments, Int64 index1, Int64 index2, string funcName, Int64 i1, Int64 i2)
+		{
+			CheckElement(arguments);
+			if ((index1 < 0) || (index1 > size))
+				throw new CodeEE(funcName + "命令の第" + i1 + "引数(" + index1 + ")は配列" + varName + "の範囲外です");
+			if ((index2 < 0) || (index2 > size))
+				throw new CodeEE(funcName + "命令の第" + i2 + "引数(" + index2 + ")は配列" + varName + "の範囲外です");
+		}
+	}
+
+
+
+	//サブクラスの詳細はVariableData以外は知らなくてよい
+	internal sealed partial class VariableData
+	{
+		#region 変数
+		private sealed class IntVariableToken : VariableToken
+		{
+			public IntVariableToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = false;
+				array = varData.DataInteger;
+			}
+			Int64[] array;
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				return array[VarCodeInt];
+			}
+
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				array[VarCodeInt] = value;
+			}
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				array[VarCodeInt] = value;
+			}
+
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				array[VarCodeInt] += value;
+				return array[VarCodeInt];
+			}
+		}
+
+		private sealed class Int1DVariableToken : VariableToken
+		{
+			public Int1DVariableToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = false;
+				array = varData.DataIntegerArray[VarCodeInt];
+				IsForbid = array.Length == 0;
+			}
+			Int64[] array;
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				return array[arguments[0]];
+			}
+
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				array[arguments[0]] = value;
+			}
+
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[0];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[i] = values[i - start];
+			}
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				for (int i = start; i < end; i++)
+					array[i] = value;
+			}
+
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				array[arguments[0]] += value;
+				return array[arguments[0]];
+			}
+			public override Int32 GetLength()
+			{ return array.Length; }
+			public override Int32 GetLength(int dimension)
+			{
+				if (dimension == 0)
+					return array.Length;
+				throw new CodeEE("配列型変数" + varName + "の存在しない次元の長さを取得しようとしました");
+			}
+			public override object GetArray() { return array; }
+
+			public override void CheckElement(Int64[] arguments, bool[] doCheck)
+			{
+				if (doCheck[0] && ((arguments[0] < 0) || (arguments[0] >= array.Length)))
+					throw new CodeEE("配列変数" + varName + "の第1引数(" + arguments[0] + ")は配列の範囲外です");
+			}
+			public override void IsArrayRangeValid(Int64[] arguments, Int64 index1, Int64 index2, string funcName, Int64 i1, Int64 i2)
+			{
+				CheckElement(arguments);
+				if ((index1 < 0) || (index1 > array.Length))
+					throw new CodeEE(funcName + "命令の第" + i1 + "引数(" + index1 + ")は配列" + varName + "の範囲外です");
+				if ((index2 < 0) || (index2 > array.Length))
+					throw new CodeEE(funcName + "命令の第" + i2 + "引数(" + index2 + ")は配列" + varName + "の範囲外です");
+			}
+		}
+
+		private sealed class Int2DVariableToken : VariableToken
+		{
+			public Int2DVariableToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = false;
+				array = varData.DataIntegerArray2D[VarCodeInt];
+				IsForbid = array.Length == 0;
+			}
+			Int64[,] array;
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				return array[arguments[0], arguments[1]];
+			}
+
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				array[arguments[0], arguments[1]] = value;
+			}
+
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[1];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[arguments[0], i] = values[i - start];
+			}
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				int a1 = array.GetLength(0);
+				int a2 = array.GetLength(1);
+				for (int i = 0; i < a1; i++)
+					for (int j = 0; j < a2; j++)
+						array[i, j] = value;
+			}
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				array[arguments[0], arguments[1]] += value;
+				return array[arguments[0], arguments[1]];
+			}
+			public override Int32 GetLength()
+			{ throw new CodeEE("2次元配列型変数" + varName + "の長さを取得しようとしました"); }
+			public override Int32 GetLength(int dimension)
+			{
+				if ((dimension == 0) || (dimension == 1))
+					return array.GetLength(dimension);
+				throw new CodeEE("配列型変数" + varName + "の存在しない次元の長さを取得しようとしました");
+			}
+			public override object GetArray() { return array; }
+
+			public override void CheckElement(Int64[] arguments, bool[] doCheck)
+			{
+				if (doCheck[0] && ((arguments[0] < 0) || (arguments[0] >= array.GetLength(0))))
+					throw new CodeEE("二次元配列" + varName + "の第1引数(" + arguments[0] + ")は配列の範囲外です");
+				if (doCheck[1] && ((arguments[1] < 0) || (arguments[1] >= array.GetLength(1))))
+					throw new CodeEE("二次元配列" + varName + "の第2引数(" + arguments[1] + ")は配列の範囲外です");
+			}
+			public override void IsArrayRangeValid(Int64[] arguments, Int64 index1, Int64 index2, string funcName, Int64 i1, Int64 i2)
+			{
+				CheckElement(arguments);
+				if ((index1 < 0) || (index1 > array.GetLength(1)))
+					throw new CodeEE(funcName + "命令の第" + i1 + "引数(" + index1 + ")は配列" + varName + "の範囲外です");
+				if ((index2 < 0) || (index2 > array.GetLength(1)))
+					throw new CodeEE(funcName + "命令の第" + i2 + "引数(" + index2 + ")は配列" + varName + "の範囲外です");
+			}
+		}
+
+		private sealed class Int3DVariableToken : VariableToken
+		{
+			public Int3DVariableToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = false;
+				array = varData.DataIntegerArray3D[VarCodeInt];
+				IsForbid = array.Length == 0;
+			}
+			Int64[, ,] array;
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				return array[arguments[0], arguments[1], arguments[2]];
+			}
+
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				array[arguments[0], arguments[1], arguments[2]] = value;
+			}
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[2];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[arguments[0], arguments[1], i] = values[i - start];
+			}
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				int a1 = array.GetLength(0);
+				int a2 = array.GetLength(1);
+				int a3 = array.GetLength(2);
+				for (int i = 0; i < a1; i++)
+					for (int j = 0; j < a2; j++)
+						for (int k = 0; k < a3; k++)
+							array[i, j, k] = value;
+			}
+
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				array[arguments[0], arguments[1], arguments[2]] += value;
+				return array[arguments[0], arguments[1], arguments[2]];
+			}
+			public override Int32 GetLength()
+			{ throw new CodeEE("3次元配列型変数" + varName + "の長さを取得しようとしました"); }
+			public override Int32 GetLength(int dimension)
+			{
+				if ((dimension == 0) || (dimension == 1) || (dimension == 2))
+					return array.GetLength(dimension);
+				throw new CodeEE("配列型変数" + varName + "の存在しない次元の長さを取得しようとしました");
+			}
+			public override object GetArray() { return array; }
+
+			public override void CheckElement(Int64[] arguments, bool[] doCheck)
+			{
+				if (doCheck[0] && ((arguments[0] < 0) || (arguments[0] >= array.GetLength(0))))
+					throw new CodeEE("三次元配列" + varName + "の第1引数(" + arguments[0] + ")は配列の範囲外です");
+				if (doCheck[1] && ((arguments[1] < 0) || (arguments[1] >= array.GetLength(1))))
+					throw new CodeEE("三次元配列" + varName + "の第2引数(" + arguments[1] + ")は配列の範囲外です");
+				if (doCheck[2] && ((arguments[2] < 0) || (arguments[2] >= array.GetLength(2))))
+					throw new CodeEE("三次元配列" + varName + "の第3引数(" + arguments[2] + ")は配列の範囲外です");
+			}
+			public override void IsArrayRangeValid(Int64[] arguments, Int64 index1, Int64 index2, string funcName, Int64 i1, Int64 i2)
+			{
+				CheckElement(arguments);
+				if ((index1 < 0) || (index1 > array.GetLength(2)))
+					throw new CodeEE(funcName + "命令の第" + i1 + "引数(" + index1 + ")は配列" + varName + "の範囲外です");
+				if ((index2 < 0) || (index2 > array.GetLength(2)))
+					throw new CodeEE(funcName + "命令の第" + i2 + "引数(" + index2 + ")は配列" + varName + "の範囲外です");
+			}
+		}
+
+		private sealed class StrVariableToken : VariableToken
+		{
+			public StrVariableToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = false;
+				array = varData.DataString;
+				IsForbid = array.Length == 0;
+			}
+			string[] array;
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				return array[VarCodeInt];
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				array[VarCodeInt] = value;
+			}
+
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				array[VarCodeInt] = value;
+			}
+
+		}
+
+		private sealed class Str1DVariableToken : VariableToken
+		{
+			public Str1DVariableToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = false;
+				array = varData.DataStringArray[VarCodeInt];
+				IsForbid = array.Length == 0;
+			}
+			string[] array;
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				//Bartoum : Str.csv variable names switch here, so we try to translate
+                return Translation.translate(array[arguments[0]], "Str", translate);
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				array[arguments[0]] = value;
+			}
+			public override void SetValue(string[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[0];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[i] = values[i - start];
+			}
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				for (int i = start; i < end; i++)
+					array[i] = value;
+			}
+			public override Int32 GetLength()
+			{ return array.Length; }
+			public override Int32 GetLength(int dimension)
+			{
+				if (dimension == 0)
+					return array.Length;
+				throw new CodeEE("配列型変数" + varName + "の存在しない次元の長さを取得しようとしました");
+			}
+			public override object GetArray() { return array; }
+
+			public override void CheckElement(Int64[] arguments, bool[] doCheck)
+			{
+				if (doCheck[0] && ((arguments[0] < 0) || (arguments[0] >= array.Length)))
+					throw new CodeEE("配列変数" + varName + "の第1引数(" + arguments[0] + ")は配列の範囲外です");
+			}
+			public override void IsArrayRangeValid(Int64[] arguments, Int64 index1, Int64 index2, string funcName, Int64 i1, Int64 i2)
+			{
+				CheckElement(arguments);
+				if ((index1 < 0) || (index1 > array.Length))
+					throw new CodeEE(funcName + "命令の第" + i1 + "引数(" + index1 + ")は配列" + varName + "の範囲外です");
+				if ((index2 < 0) || (index2 > array.Length))
+					throw new CodeEE(funcName + "命令の第" + i2 + "引数(" + index2 + ")は配列" + varName + "の範囲外です");
+			}
+		}
+
+		private sealed class Str2DVariableToken : VariableToken
+		{
+			public Str2DVariableToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = false;
+				array = varData.DataStringArray2D[VarCodeInt];
+				IsForbid = array.Length == 0;
+			}
+			string[,] array;
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				return array[arguments[0], arguments[1]];
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				array[arguments[0], arguments[1]] = value;
+			}
+
+			public override void SetValue(string[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[1];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[arguments[0], i] = values[i - start];
+			}
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				int a1 = array.GetLength(0);
+				int a2 = array.GetLength(1);
+				for (int i = 0; i < a1; i++)
+					for (int j = 0; j < a2; j++)
+						array[i, j] = value;
+			}
+			public override Int32 GetLength()
+			{ throw new CodeEE("2次元配列型変数" + varName + "の長さを取得しようとしました"); }
+			public override Int32 GetLength(int dimension)
+			{
+				if ((dimension == 0) || (dimension == 1))
+					return array.GetLength(dimension);
+				throw new CodeEE("配列型変数" + varName + "の存在しない次元の長さを取得しようとしました");
+			}
+			public override object GetArray() { return array; }
+
+			public override void CheckElement(Int64[] arguments, bool[] doCheck)
+			{
+				if (doCheck[0] && ((arguments[0] < 0) || (arguments[0] >= array.GetLength(0))))
+					throw new CodeEE("二次元配列" + varName + "の第1引数(" + arguments[0] + ")は配列の範囲外です");
+				if (doCheck[1] && ((arguments[1] < 0) || (arguments[1] >= array.GetLength(1))))
+					throw new CodeEE("二次元配列" + varName + "の第2引数(" + arguments[1] + ")は配列の範囲外です");
+			}
+			public override void IsArrayRangeValid(Int64[] arguments, Int64 index1, Int64 index2, string funcName, Int64 i1, Int64 i2)
+			{
+				CheckElement(arguments);
+				if ((index1 < 0) || (index1 > array.GetLength(1)))
+					throw new CodeEE(funcName + "命令の第" + i1 + "引数(" + index1 + ")は配列" + varName + "の範囲外です");
+				if ((index2 < 0) || (index2 > array.GetLength(1)))
+					throw new CodeEE(funcName + "命令の第" + i2 + "引数(" + index2 + ")は配列" + varName + "の範囲外です");
+			}
+		}
+
+		private sealed class Str3DVariableToken : VariableToken
+		{
+			public Str3DVariableToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = false;
+				array = varData.DataStringArray3D[VarCodeInt];
+				IsForbid = array.Length == 0;
+			}
+			string[, ,] array;
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				return array[arguments[0], arguments[1], arguments[2]];
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				array[arguments[0], arguments[1], arguments[2]] = value;
+			}
+
+			public override void SetValue(string[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[2];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[arguments[0], arguments[1], i] = values[i - start];
+			}
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				int a1 = array.GetLength(0);
+				int a2 = array.GetLength(1);
+				int a3 = array.GetLength(2);
+				for (int i = 0; i < a1; i++)
+					for (int j = 0; j < a2; j++)
+						for (int k = 0; k < a3; k++)
+							array[i, j, k] = value;
+			}
+			public override Int32 GetLength()
+			{ throw new CodeEE("3次元配列型変数" + varName + "の長さを取得しようとしました"); }
+			public override Int32 GetLength(int dimension)
+			{
+				if ((dimension == 0) || (dimension == 1) || (dimension == 2))
+					return array.GetLength(dimension);
+				throw new CodeEE("配列型変数" + varName + "の存在しない次元の長さを取得しようとしました");
+			}
+			public override object GetArray() { return array; }
+
+			public override void CheckElement(Int64[] arguments, bool[] doCheck)
+			{
+				if (doCheck[0] && ((arguments[0] < 0) || (arguments[0] >= array.GetLength(0))))
+					throw new CodeEE("三次元配列" + varName + "の第1引数(" + arguments[0] + ")は配列の範囲外です");
+				if (doCheck[1] && ((arguments[1] < 0) || (arguments[1] >= array.GetLength(1))))
+					throw new CodeEE("三次元配列" + varName + "の第2引数(" + arguments[1] + ")は配列の範囲外です");
+				if (doCheck[2] && ((arguments[2] < 0) || (arguments[2] >= array.GetLength(2))))
+					throw new CodeEE("三次元配列" + varName + "の第3引数(" + arguments[2] + ")は配列の範囲外です");
+			}
+			public override void IsArrayRangeValid(Int64[] arguments, Int64 index1, Int64 index2, string funcName, Int64 i1, Int64 i2)
+			{
+				CheckElement(arguments);
+				if ((index1 < 0) || (index1 > array.GetLength(2)))
+					throw new CodeEE(funcName + "命令の第" + i1 + "引数(" + index1 + ")は配列" + varName + "の範囲外です");
+				if ((index2 < 0) || (index2 > array.GetLength(2)))
+					throw new CodeEE(funcName + "命令の第" + i2 + "引数(" + index2 + ")は配列" + varName + "の範囲外です");
+			}
+		}
+
+		private sealed class CharaIntVariableToken : CharaVariableToken
+		{
+			public CharaIntVariableToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = false;
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				return chara.DataInteger[VarCodeInt];
+			}
+
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				chara.DataInteger[VarCodeInt] = value;
+			}
+
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				varData.CharacterList[charaPos].setValueAll(VarCodeInt, value);
+				//CharacterData chara = varData.CharacterList[charaPos];
+				//chara.DataInteger[VarCodeInt] = value;
+			}
+
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				chara.DataInteger[VarCodeInt] += value;
+				return chara.DataInteger[VarCodeInt];
+			}
+		}
+
+		private sealed class CharaInt1DVariableToken : CharaVariableToken
+		{
+			public CharaInt1DVariableToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = false;
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				return chara.DataIntegerArray[VarCodeInt][arguments[1]];
+			}
+
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				chara.DataIntegerArray[VarCodeInt][arguments[1]] = value;
+			}
+
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				Int64[] array = chara.DataIntegerArray[VarCodeInt];
+				int start = (int)arguments[1];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[i] = values[i - start];
+			}
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				varData.CharacterList[charaPos].setValueAll1D(VarCodeInt, value, start, end);
+				//CharacterData chara = varData.CharacterList[charaPos];
+				//Int64[] array = chara.DataIntegerArray[VarCodeInt];
+				//for (int i = start; i < end; i++)
+				//    array[i] = value;
+			}
+
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				chara.DataIntegerArray[VarCodeInt][arguments[1]] += value;
+				return chara.DataIntegerArray[VarCodeInt][arguments[1]];
+			}
+
+			public override object GetArrayChara(int charano)
+			{
+				CharacterData chara = varData.CharacterList[charano];
+				return chara.DataIntegerArray[VarCodeInt];
+			}
+
+		}
+
+
+		private sealed class CharaStrVariableToken : CharaVariableToken
+		{
+			public CharaStrVariableToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = false;
+			}
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				return chara.DataString[VarCodeInt];
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				chara.DataString[VarCodeInt] = value;
+			}
+
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				varData.CharacterList[charaPos].setValueAll(VarCodeInt, value);
+				//CharacterData chara = varData.CharacterList[charaPos];
+				//chara.DataString[VarCodeInt] = value;
+			}
+
+
+		}
+
+		private sealed class CharaStr1DVariableToken : CharaVariableToken
+		{
+			public CharaStr1DVariableToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = false;
+			}
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				return chara.DataStringArray[VarCodeInt][arguments[1]];
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				chara.DataStringArray[VarCodeInt][arguments[1]] = value;
+			}
+
+			public override void SetValue(string[] values, Int64[] arguments)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				string[] array = chara.DataStringArray[VarCodeInt];
+				int start = (int)arguments[1];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[i] = values[i - start];
+			}
+
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				varData.CharacterList[charaPos].setValueAll1D(VarCodeInt, value, start, end);
+				//CharacterData chara = varData.CharacterList[charaPos];
+				//String[] array = chara.DataStringArray[VarCodeInt];
+				//for (int i = start; i < end; i++)
+				//    array[i] = value;
+			}
+
+			public override object GetArrayChara(int charano)
+			{
+				CharacterData chara = varData.CharacterList[charano];
+				return chara.DataStringArray[VarCodeInt];
+			}
+
+		}
+
+		private sealed class CharaInt2DVariableToken : CharaVariableToken
+		{
+			public CharaInt2DVariableToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = false;
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				return chara.DataIntegerArray2D[VarCodeInt][arguments[1], arguments[2]];
+			}
+
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				chara.DataIntegerArray2D[VarCodeInt][arguments[1], arguments[2]] = value;
+			}
+
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				Int64[,] array = chara.DataIntegerArray2D[VarCodeInt];
+				int start = (int)arguments[2];
+				int end = start + values.Length;
+				int index1 = (int)arguments[1];
+				for (int i = start; i < end; i++)
+					array[index1, i] = values[i - start];
+			}
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				varData.characterList[charaPos].setValueAll2D(VarCodeInt, value);
+				//CharacterData chara = varData.CharacterList[charaPos];
+				//Int64[,] array = chara.DataIntegerArray2D[VarCodeInt];
+				//int a1 = array.GetLength(0);
+				//int a2 = array.GetLength(1);
+				//for (int i = 0; i < a1; i++)
+				//    for (int j = 0; j < a2; j++)
+				//        array[i, j] = value;
+			}
+
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				chara.DataIntegerArray2D[VarCodeInt][arguments[1], arguments[2]] += value;
+				return chara.DataIntegerArray2D[VarCodeInt][arguments[1], arguments[2]];
+			}
+
+			public override object GetArrayChara(int charano)
+			{
+				CharacterData chara = varData.CharacterList[charano];
+				return chara.DataIntegerArray2D[VarCodeInt];
+			}
+
+		}
+
+		private sealed class CharaStr2DVariableToken : CharaVariableToken
+		{
+			public CharaStr2DVariableToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = false;
+			}
+
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				return chara.DataStringArray2D[VarCodeInt][arguments[1], arguments[2]];
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				chara.DataStringArray2D[VarCodeInt][arguments[1], arguments[2]] = value;
+			}
+
+			public override void SetValue(string[] values, Int64[] arguments)
+			{
+				CharacterData chara = varData.CharacterList[(int)arguments[0]];
+				string[,] array = chara.DataStringArray2D[VarCodeInt];
+				int start = (int)arguments[2];
+				int end = start + values.Length;
+				int index1 = (int)arguments[1];
+				for (int i = start; i < end; i++)
+					array[index1, i] = values[i - start];
+			}
+
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				varData.characterList[charaPos].setValueAll2D(VarCodeInt, value);
+				//CharacterData chara = varData.CharacterList[charaPos];
+				//String[,] array = chara.DataStringArray2D[VarCodeInt];
+				//int a1 = array.GetLength(0);
+				//int a2 = array.GetLength(1);
+				//for (int i = 0; i < a1; i++)
+				//    for (int j = 0; j < a2; j++)
+				//        array[i, j] = value;
+			}
+
+
+			public override object GetArrayChara(int charano)
+			{
+				CharacterData chara = varData.CharacterList[charano];
+				return chara.DataStringArray2D[VarCodeInt];
+			}
+
+		}
+		#endregion
+		#region 定数
+		private abstract class ConstantToken : VariableToken
+		{
+			public ConstantToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = true;
+			}
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{ throw new CodeEE("読み取り専用の変数" + varName + "に代入しようとしました"); }
+			public override void SetValue(string value, Int64[] arguments)
+			{ throw new CodeEE("読み取り専用の変数" + varName + "に代入しようとしました"); }
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{ throw new CodeEE("読み取り専用の変数" + varName + "に代入しようとしました"); }
+			public override void SetValue(string[] values, Int64[] arguments)
+			{ throw new CodeEE("読み取り専用の変数" + varName + "に代入しようとしました"); }
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{ throw new CodeEE("読み取り専用の変数" + varName + "に代入しようとしました"); }
+		}
+
+		private sealed class IntConstantToken : ConstantToken
+		{
+			public IntConstantToken(VariableCode varCode, VariableData varData, Int64 i)
+				: base(varCode, varData)
+			{
+				this.i = i;
+			}
+			Int64 i;
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				return i;
+			}
+		}
+		private sealed class StrConstantToken : ConstantToken
+		{
+			public StrConstantToken(VariableCode varCode, VariableData varData, string s)
+				: base(varCode, varData)
+			{
+				this.s = s;
+			}
+			string s;
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				return s;
+			}
+		}
+		private sealed class Int1DConstantToken : ConstantToken
+		{
+			public Int1DConstantToken(VariableCode varCode, VariableData varData, Int64[] array)
+				: base(varCode, varData)
+			{
+				this.array = array;
+				IsForbid = array.Length == 0;
+			}
+			Int64[] array;
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				return array[arguments[0]];
+			}
+			public override Int32 GetLength()
+			{ return array.Length; }
+			public override Int32 GetLength(int dimension)
+			{
+				if (dimension == 0)
+					return array.Length;
+				throw new CodeEE("配列型変数" + varName + "の存在しない次元の長さを取得しようとしました");
+			}
+			public override object GetArray() { return array; }
+
+			public override void CheckElement(Int64[] arguments, bool[] doCheck)
+			{
+				if (doCheck[0] && ((arguments[0] < 0) || (arguments[0] >= array.Length)))
+					throw new CodeEE("配列変数" + varName + "の第1引数(" + arguments[0] + ")は配列の範囲外です");
+			}
+			public override void IsArrayRangeValid(Int64[] arguments, Int64 index1, Int64 index2, string funcName, Int64 i1, Int64 i2)
+			{
+				CheckElement(arguments);
+				if ((index1 < 0) || (index1 > array.Length))
+					throw new CodeEE(funcName + "命令の第" + i1 + "引数(" + index1 + ")は配列" + varName + "の範囲外です");
+				if ((index2 < 0) || (index2 > array.Length))
+					throw new CodeEE(funcName + "命令の第" + i2 + "引数(" + index2 + ")は配列" + varName + "の範囲外です");
+			}
+		}
+
+		private sealed class Str1DConstantToken : ConstantToken
+		{
+			string name;
+			public Str1DConstantToken(VariableCode varCode, VariableData varData, string[] array)
+				: base(varCode, varData)
+			{
+				this.array = array;
+				IsForbid = array.Length == 0;
+				name = "Base";
+			}
+			
+			public Str1DConstantToken(VariableCode varCode, VariableData varData, string pname)
+				: base(varCode, varData)
+			{
+				name = pname;
+				array = varData.constant.GetCsvNameList(varCode);
+				IsForbid = array.Length == 0;
+			}
+
+			string[] array;
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+                //Changes by Bartoum
+
+                //This is where the _TR files translate. They can only translate stuff that is on a print line
+                //Exemple PRINTFORM [%TALENTNAME:X%]
+
+
+                return Translation.translate(array[arguments[0]], name, translate);
+
+
+            }
+			public override Int32 GetLength()
+			{ return array.Length; }
+			public override Int32 GetLength(int dimension)
+			{
+				if (dimension == 0)
+					return array.Length;
+				throw new CodeEE("配列型変数" + varName + "の存在しない次元の長さを取得しようとしました");
+			}
+			public override object GetArray() { return array; }
+
+			public override void CheckElement(Int64[] arguments, bool[] doCheck)
+			{
+				if (doCheck[0] && ((arguments[0] < 0) || (arguments[0] >= array.Length)))
+					throw new CodeEE("配列変数" + varName + "の第1引数(" + arguments[0] + ")は配列の範囲外です");
+			}
+			public override void IsArrayRangeValid(Int64[] arguments, Int64 index1, Int64 index2, string funcName, Int64 i1, Int64 i2)
+			{
+				CheckElement(arguments);
+				if ((index1 < 0) || (index1 > array.Length))
+					throw new CodeEE(funcName + "命令の第" + i1 + "引数(" + index1 + ")は配列" + varName + "の範囲外です");
+				if ((index2 < 0) || (index2 > array.Length))
+					throw new CodeEE(funcName + "命令の第" + i2 + "引数(" + index2 + ")は配列" + varName + "の範囲外です");
+			}
+		}
+
+		#endregion
+		#region 特殊処理
+
+		private abstract class PseudoVariableToken : VariableToken
+		{
+			protected PseudoVariableToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = false;
+			}
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{ throw new CodeEE("擬似変数" + varName + "に代入しようとしました"); }
+			public override void SetValue(string value, Int64[] arguments)
+			{ throw new CodeEE("擬似変数" + varName + "に代入しようとしました"); }
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{ throw new CodeEE("擬似変数" + varName + "に代入しようとしました"); }
+			public override void SetValue(string[] values, Int64[] arguments)
+			{ throw new CodeEE("擬似変数" + varName + "に代入しようとしました"); }
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{ throw new CodeEE("擬似変数" + varName + "に代入しようとしました"); }
+			public override Int32 GetLength()
+			{ throw new CodeEE("擬似変数" + varName + "の長さを取得しようとしました"); }
+			public override Int32 GetLength(int dimension)
+			{ throw new CodeEE("擬似変数" + varName + "の長さを取得しようとしました"); }
+			public override object GetArray()
+			{ throw new CodeEE("擬似変数" + varName + "の配列を取得しようとしました"); }
+		}
+
+
+		private sealed class RandToken : PseudoVariableToken
+		{
+			public RandToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				Int64 i = arguments[0];
+				if (i <= 0)
+					throw new CodeEE("RANDの引数に0以下の値(" + i + ")が指定されました");
+				return exm.VEvaluator.GetNextRand(i);
+			}
+		}
+		private sealed class CompatiRandToken : PseudoVariableToken
+		{
+			public CompatiRandToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				Int64 i = arguments[0];
+				if (i == 0)
+					return 0L;
+				if (i < 0)
+					i = -i;
+				return exm.VEvaluator.GetNextRand(32768) % i;//0-32767の乱数を引数で除算した余り
+			}
+		}
+
+		private sealed class CHARANUM_Token : PseudoVariableToken
+		{
+			public CHARANUM_Token(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				return varData.CharacterList.Count;
+			}
+		}
+
+		private sealed class LASTLOAD_TEXT_Token : PseudoVariableToken
+		{
+			public LASTLOAD_TEXT_Token(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+			}
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				return varData.LastLoadText;
+			}
+		}
+
+		private sealed class LASTLOAD_VERSION_Token : PseudoVariableToken
+		{
+			public LASTLOAD_VERSION_Token(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				return varData.LastLoadVersion;
+			}
+		}
+
+		private sealed class LASTLOAD_NO_Token : PseudoVariableToken
+		{
+			public LASTLOAD_NO_Token(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				return varData.LastLoadNo;
+			}
+		}
+		private sealed class LINECOUNT_Token : PseudoVariableToken
+		{
+			public LINECOUNT_Token(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				return exm.Console.LineCount;
+			}
+		}
+
+		private sealed class WINDOW_TITLE_Token : VariableToken
+		{
+			public WINDOW_TITLE_Token(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = false;
+			}
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				return GlobalStatic.Console.GetWindowTitle();
+			}
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				GlobalStatic.Console.SetWindowTitle(value);
+			}
+		}
+
+		private sealed class MONEYLABEL_Token : VariableToken
+		{
+			public MONEYLABEL_Token(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = true;
+			}
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				return Config.MoneyLabel;
+			}
+		}
+
+		private sealed class DRAWLINESTR_Token : VariableToken
+		{
+			public DRAWLINESTR_Token(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = true;
+			}
+			public override string GetStrValue(ExpressionMediator exm, long[] arguments, bool translate=false)
+			{
+				return exm.Console.getDefStBar();
+			}
+		}
+
+		private sealed class EmptyStrToken : PseudoVariableToken
+		{
+			public EmptyStrToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = true;
+			}
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				return "";
+			}
+		}
+		private sealed class EmptyIntToken : PseudoVariableToken
+		{
+			public EmptyIntToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = true;
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				return 0L;
+			}
+		}
+
+		private sealed class Debug__FILE__Token : PseudoVariableToken
+		{
+			public Debug__FILE__Token(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = true;
+			}
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				LogicalLine line = exm.Process.GetScaningLine();
+				if ((line == null) || (line.Position == null))
+					return "";
+				return line.Position.Filename;
+			}
+		}
+
+		private sealed class Debug__FUNCTION__Token : PseudoVariableToken
+		{
+			public Debug__FUNCTION__Token(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = true;
+			}
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				LogicalLine line = exm.Process.GetScaningLine();
+				if ((line == null) || (line.ParentLabelLine == null))
+					return "";//システム待機中のデバッグモードから呼び出し
+				return line.ParentLabelLine.LabelName;
+			}
+		}
+		private sealed class Debug__LINE__Token : PseudoVariableToken
+		{
+			public Debug__LINE__Token(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = true;
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				LogicalLine line = exm.Process.GetScaningLine();
+				if ((line == null) || (line.Position == null))
+					return -1L;
+				return line.Position.LineNo;
+			}
+		}
+
+		private sealed class ISTIMEOUTToken : PseudoVariableToken
+		{
+			public ISTIMEOUTToken(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = false;
+			}
+			public override long GetIntValue(ExpressionMediator exm, long[] arguments)
+			{
+				return Convert.ToInt64(GlobalStatic.Console.IsTimeOut);
+			}
+		}
+
+		private sealed class __INT_MAX__Token : PseudoVariableToken
+		{
+			public __INT_MAX__Token(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = true;
+			}
+			public override long GetIntValue(ExpressionMediator exm, long[] arguments)
+			{
+				return Int64.MaxValue;
+			}
+		}
+		private sealed class __INT_MIN__Token : PseudoVariableToken
+		{
+			public __INT_MIN__Token(VariableCode varCode, VariableData varData)
+				: base(varCode, varData)
+			{
+				CanRestructure = true;
+			}
+			public override long GetIntValue(ExpressionMediator exm, long[] arguments)
+			{
+				return Int64.MinValue;
+			}
+		}
+
+        private sealed class EMUERA_VERSIONToken : PseudoVariableToken
+        {
+            public EMUERA_VERSIONToken(VariableCode varCode, VariableData varData)
+                :base(varCode, varData)
+            {
+                CanRestructure = true;
+            }
+            public override string GetStrValue(ExpressionMediator exm, long[] arguments, bool translate=false)
+            {
+                return GlobalStatic.MainWindow.InternalEmueraVer;
+            }
+
+        }
+
+		#endregion
+		#region LOCAL
+
+
+		private sealed class LocalInt1DVariableToken : LocalVariableToken
+		{
+			public LocalInt1DVariableToken(VariableCode varCode, VariableData varData, string subId, int size)
+				: base(varCode, varData, subId, size)
+			{
+			}
+			Int64[] array;
+
+			public override void SetDefault()
+			{
+				if (array != null)
+					Array.Clear(array, 0, size);
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				if (array == null)
+					array = new Int64[size];
+				return array[arguments[0]];
+			}
+
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				if (array == null)
+					array = new Int64[size];
+				array[arguments[0]] = value;
+			}
+
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{
+				if (array == null)
+					array = new Int64[size];
+				int start = (int)arguments[0];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[i] = values[i - start];
+			}
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				if (array == null)
+					array = new Int64[size];
+				for (int i = start; i < end; i++)
+					array[i] = value;
+			}
+
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				if (array == null)
+					array = new Int64[size];
+				array[arguments[0]] += value;
+				return array[arguments[0]];
+			}
+
+			public override object GetArray()
+			{
+				if (array == null)
+					array = new Int64[size];
+				return array;
+			}
+
+			public override void resize(int newSize)
+			{
+				size = newSize;
+				array = null;
+			}
+		}
+
+		
+		//Bartoum: this is where ARGS and LOCALS are
+		private sealed class LocalStr1DVariableToken : LocalVariableToken
+		{
+			public LocalStr1DVariableToken(VariableCode varCode, VariableData varData, string subId, int size)
+				: base(varCode, varData, subId, size)
+			{
+			}
+			string[] array;
+			public override void SetDefault()
+			{
+				if (array != null)
+					Array.Clear(array, 0, size);
+			}
+
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				if (array == null)
+					array = new string[size];
+				return array[arguments[0]];
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				if (array == null)
+					array = new string[size];
+				array[arguments[0]] = value;
+			}
+
+			public override void SetValue(string[] values, Int64[] arguments)
+			{
+				if (array == null)
+					array = new string[size];
+				int start = (int)arguments[0];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[i] = values[i - start];
+			}
+
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				if (array == null)
+					array = new string[size];
+				for (int i = start; i < end; i++)
+					array[i] = value;
+			}
+
+			public override object GetArray()
+			{
+				if (array == null)
+					array = new string[size];
+				return array;
+			}
+
+			public override void resize(int newSize)
+			{
+				size = newSize;
+				array = null;
+			}
+
+		}
+
+		#endregion
+		#region userdef
+
+		//1808beta009 廃止 private static と統合
+		//private sealed class UserDefinedInt1DVariableToken : UserDefinedVariableToken
+
+		#region static (広域変数とprivate static の両方を含む)
+		private sealed class StaticInt1DVariableToken : UserDefinedVariableToken
+		{
+			public StaticInt1DVariableToken(UserDefinedVariableData data)
+				: base(VariableCode.VAR, data)
+			{
+				int[] sizes = data.Lengths;
+				IsStatic = true;
+				array = new Int64[sizes[0]];
+				defArray = data.DefaultInt;
+				if (defArray != null)
+					Array.Copy(defArray, array, defArray.Length);
+			}
+			Int64[] array;
+			Int64[] defArray;
+			public override void SetDefault()
+			{
+				Array.Clear(array, 0, totalSize);
+				if (defArray != null)
+					Array.Copy(defArray, array, defArray.Length);
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				return array[arguments[0]];
+			}
+
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				array[arguments[0]] = value;
+			}
+
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[0];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[i] = values[i - start];
+			}
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				for (int i = start; i < end; i++)
+					array[i] = value;
+			}
+
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				array[arguments[0]] += value;
+				return array[arguments[0]];
+			}
+			public override object GetArray() { return array; }
+			public override void In() { }
+			public override void Out() { }
+
+		}
+
+		private sealed class StaticInt2DVariableToken : UserDefinedVariableToken
+		{
+			public StaticInt2DVariableToken(UserDefinedVariableData data)
+				: base(VariableCode.VAR2D, data)
+			{
+				int[] sizes = data.Lengths;
+				IsStatic = true;
+				array = new Int64[sizes[0], sizes[1]];
+			}
+			Int64[,] array;
+			public override void SetDefault()
+			{
+				Array.Clear(array, 0, totalSize);
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				return array[arguments[0], arguments[1]];
+			}
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				array[arguments[0], arguments[1]] = value;
+			}
+
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[1];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[arguments[0], i] = values[i - start];
+			}
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				int a1 = array.GetLength(0);
+				int a2 = array.GetLength(1);
+				for (int i = 0; i < a1; i++)
+					for (int j = 0; j < a2; j++)
+						array[i, j] = value;
+			}
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				array[arguments[0], arguments[1]] += value;
+				return array[arguments[0], arguments[1]];
+			}
+			public override object GetArray() { return array; }
+			public override void In() { }
+			public override void Out() { }
+
+		}
+		private sealed class StaticInt3DVariableToken : UserDefinedVariableToken
+		{
+			public StaticInt3DVariableToken(UserDefinedVariableData data)
+				: base(VariableCode.VAR3D, data)
+			{
+				int[] sizes = data.Lengths;
+				IsStatic = true;
+				array = new Int64[sizes[0], sizes[1], sizes[2]];
+			}
+			Int64[, ,] array;
+			public override void SetDefault()
+			{
+				Array.Clear(array, 0, totalSize);
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				return array[arguments[0], arguments[1], arguments[2]];
+			}
+
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				array[arguments[0], arguments[1], arguments[2]] = value;
+			}
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[2];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[arguments[0], arguments[1], i] = values[i - start];
+			}
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				int a1 = array.GetLength(0);
+				int a2 = array.GetLength(1);
+				int a3 = array.GetLength(2);
+				for (int i = 0; i < a1; i++)
+					for (int j = 0; j < a2; j++)
+						for (int k = 0; k < a3; k++)
+							array[i, j, k] = value;
+			}
+
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				array[arguments[0], arguments[1], arguments[2]] += value;
+				return array[arguments[0], arguments[1], arguments[2]];
+			}
+			public override object GetArray() { return array; }
+			public override void In() { }
+			public override void Out() { }
+
+		}
+		
+		
+		//Bartoum: this is where user string variables are
+		private sealed class StaticStr1DVariableToken : UserDefinedVariableToken
+		{
+			public StaticStr1DVariableToken(UserDefinedVariableData data)
+				: base(VariableCode.VARS, data)
+			{
+				int[] sizes = data.Lengths;
+				IsStatic = true;
+				array = new string[sizes[0]];
+				defArray = data.DefaultStr;
+				if (defArray != null)
+					Array.Copy(defArray, array, defArray.Length);
+			}
+			string[] array;
+			string[] defArray;
+			public override void SetDefault()
+			{
+				Array.Clear(array, 0, totalSize);
+				if (defArray != null)
+					Array.Copy(defArray, array, defArray.Length);
+			}
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				return array[arguments[0]];
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				array[arguments[0]] = value;
+			}
+
+			public override void SetValue(string[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[0];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[i] = values[i - start];
+			}
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				for (int i = start; i < end; i++)
+					array[i] = value;
+			}
+			public override object GetArray() { return array; }
+			public override void In() { }
+			public override void Out() { }
+		}
+		
+		
+		
+		
+		
+		
+		
+		
+		
+		private sealed class StaticStr2DVariableToken : UserDefinedVariableToken
+		{
+			public StaticStr2DVariableToken(UserDefinedVariableData data)
+				: base(VariableCode.VARS2D, data)
+			{
+				int[] sizes = data.Lengths;
+				IsStatic = true;
+				array = new string[sizes[0], sizes[1]];
+			}
+			string[,] array;
+			public override void SetDefault()
+			{
+				Array.Clear(array, 0, totalSize);
+			}
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				return array[arguments[0], arguments[1]];
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				array[arguments[0], arguments[1]] = value;
+			}
+
+			public override void SetValue(string[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[1];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[arguments[0], i] = values[i - start];
+			}
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				int a1 = array.GetLength(0);
+				int a2 = array.GetLength(1);
+				for (int i = 0; i < a1; i++)
+					for (int j = 0; j < a2; j++)
+						array[i, j] = value;
+			}
+			public override object GetArray() { return array; }
+			public override void In() { }
+			public override void Out() { }
+		}
+
+		private sealed class StaticStr3DVariableToken : UserDefinedVariableToken
+		{
+			public StaticStr3DVariableToken(UserDefinedVariableData data)
+				: base(VariableCode.VARS3D, data)
+			{
+				int[] sizes = data.Lengths;
+				IsStatic = true;
+				array = new string[sizes[0], sizes[1], sizes[2]];
+			}
+			string[, ,] array;
+			public override void SetDefault()
+			{
+				Array.Clear(array, 0, totalSize);
+			}
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				return array[arguments[0], arguments[1], arguments[2]];
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				array[arguments[0], arguments[1], arguments[2]] = value;
+			}
+
+			public override void SetValue(string[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[2];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[arguments[0], arguments[1], i] = values[i - start];
+			}
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				int a1 = array.GetLength(0);
+				int a2 = array.GetLength(1);
+				int a3 = array.GetLength(2);
+				for (int i = 0; i < a1; i++)
+					for (int j = 0; j < a2; j++)
+						for (int k = 0; k < a3; k++)
+							array[i, j, k] = value;
+			}
+			public override object GetArray() { return array; }
+			public override void In() { }
+			public override void Out() { }
+		}
+		#endregion
+		#region private dynamic
+
+		private sealed class PrivateInt1DVariableToken : UserDefinedVariableToken
+		{
+			public PrivateInt1DVariableToken(UserDefinedVariableData data)
+				: base(VariableCode.VAR, data)
+			{
+				int[] sizes = data.Lengths;
+				IsStatic = false;
+				arrayList = new List<Int64[]>();
+				defArray = data.DefaultInt;
+			}
+			readonly List<Int64[]> arrayList;
+			Int64[] array;
+			Int64[] defArray;
+			//int counter = 0;
+			public override void SetDefault()
+			{
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				return array[arguments[0]];
+			}
+
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				array[arguments[0]] = value;
+			}
+
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[0];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[i] = values[i - start];
+			}
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				for (int i = start; i < end; i++)
+					array[i] = value;
+			}
+
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				array[arguments[0]] += value;
+				return array[arguments[0]];
+			}
+			public override object GetArray() { return array; }
+
+			public override void In()
+			{
+				if (array != null)
+					arrayList.Add(array);
+				//counter++;
+				array = new Int64[sizes[0]];
+				if (defArray != null)
+					Array.Copy(defArray, array, defArray.Length);
+			}
+
+			public override void Out()
+			{
+				//counter--;
+				//arrayList.RemoveAt(arrayList.Count - 1);
+				if (arrayList.Count > 0)
+				{
+					array = arrayList[arrayList.Count - 1];
+					arrayList.RemoveAt(arrayList.Count - 1);
+				}
+				else
+					array = null;
+			}
+		}
+		private sealed class PrivateInt2DVariableToken : UserDefinedVariableToken
+		{
+			public PrivateInt2DVariableToken(UserDefinedVariableData data)
+				: base(VariableCode.VAR2D, data)
+			{
+				int[] sizes = data.Lengths;
+				IsStatic = false;
+				arrayList = new List<Int64[,]>();
+			}
+			readonly List<Int64[,]> arrayList;
+			Int64[,] array;
+			//int counter = 0;
+			public override void SetDefault() { }
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				return array[arguments[0], arguments[1]];
+			}
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				array[arguments[0], arguments[1]] = value;
+			}
+
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[1];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[arguments[0], i] = values[i - start];
+			}
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				int a1 = array.GetLength(0);
+				int a2 = array.GetLength(1);
+				for (int i = 0; i < a1; i++)
+					for (int j = 0; j < a2; j++)
+						array[i, j] = value;
+			}
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				array[arguments[0], arguments[1]] += value;
+				return array[arguments[0], arguments[1]];
+			}
+			public override object GetArray() { return array; }
+
+			public override void In()
+			{
+				if (array != null)
+					arrayList.Add(array);
+				//counter++;
+				array = new Int64[sizes[0], sizes[1]];
+			}
+
+			public override void Out()
+			{
+				//counter--;
+				//arrayList.RemoveAt(arrayList.Count - 1);
+				if (arrayList.Count > 0)
+				{
+					array = arrayList[arrayList.Count - 1];
+					arrayList.RemoveAt(arrayList.Count - 1);
+				}
+				else
+					array = null;
+			}
+		}
+		private sealed class PrivateInt3DVariableToken : UserDefinedVariableToken
+		{
+			public PrivateInt3DVariableToken(UserDefinedVariableData data)
+				: base(VariableCode.VAR3D, data)
+			{
+				int[] sizes = data.Lengths;
+				IsStatic = false;
+				arrayList = new List<Int64[, ,]>();
+			}
+			readonly List<Int64[, ,]> arrayList;
+			Int64[, ,] array;
+			//int counter = 0;
+			public override void SetDefault() { }
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				return array[arguments[0], arguments[1], arguments[2]];
+			}
+
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				array[arguments[0], arguments[1], arguments[2]] = value;
+			}
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[2];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[arguments[0], arguments[1], i] = values[i - start];
+			}
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				int a1 = array.GetLength(0);
+				int a2 = array.GetLength(1);
+				int a3 = array.GetLength(2);
+				for (int i = 0; i < a1; i++)
+					for (int j = 0; j < a2; j++)
+						for (int k = 0; k < a3; k++)
+							array[i, j, k] = value;
+			}
+
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				array[arguments[0], arguments[1], arguments[2]] += value;
+				return array[arguments[0], arguments[1], arguments[2]];
+			}
+			public override object GetArray() { return array; }
+
+			public override void In()
+			{
+				if (array != null)
+					arrayList.Add(array);
+				//counter++;
+				array = new Int64[sizes[0], sizes[1], sizes[2]];
+			}
+
+			public override void Out()
+			{
+				//counter--;
+				//arrayList.RemoveAt(arrayList.Count - 1);
+				if (arrayList.Count > 0)
+				{
+					array = arrayList[arrayList.Count - 1];
+					arrayList.RemoveAt(arrayList.Count - 1);
+				}
+				else
+					array = null;
+			}
+		}
+
+		private sealed class PrivateStr1DVariableToken : UserDefinedVariableToken
+		{
+			public PrivateStr1DVariableToken(UserDefinedVariableData data)
+				: base(VariableCode.VARS, data)
+			{
+				int[] sizes = data.Lengths;
+				IsStatic = false;
+				arrayList = new List<string[]>();
+				defArray = data.DefaultStr;
+			}
+			//int counter = 0;
+			readonly List<string[]> arrayList;
+			string[] array;
+			string[] defArray;
+			public override void SetDefault()
+			{
+			}
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				return array[arguments[0]];
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				array[arguments[0]] = value;
+			}
+
+			public override void SetValue(string[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[0];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[i] = values[i - start];
+			}
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				for (int i = start; i < end; i++)
+					array[i] = value;
+			}
+			public override object GetArray() { return array; }
+			public override void In()
+			{
+				//counter++;
+				if (array != null)
+					arrayList.Add(array);
+				array = new string[sizes[0]];
+				if (defArray != null)
+					Array.Copy(defArray, array, defArray.Length);
+				//arrayList.Add(array);
+			}
+
+			public override void Out()
+			{
+				//counter--;
+				//arrayList.RemoveAt(arrayList.Count - 1);
+				if (arrayList.Count > 0)
+				{
+					array = arrayList[arrayList.Count - 1];
+					arrayList.RemoveAt(arrayList.Count - 1);
+				}
+				else
+					array = null;
+			}
+		}
+
+		private sealed class PrivateStr2DVariableToken : UserDefinedVariableToken
+		{
+			public PrivateStr2DVariableToken(UserDefinedVariableData data)
+				: base(VariableCode.VARS2D, data)
+			{
+				int[] sizes = data.Lengths;
+				IsStatic = false;
+				arrayList = new List<string[,]>();
+			}
+			//int counter = 0;
+			readonly List<string[,]> arrayList;
+			string[,] array;
+			public override void SetDefault()
+			{
+			}
+
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				return array[arguments[0], arguments[1]];
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				array[arguments[0], arguments[1]] = value;
+			}
+
+			public override void SetValue(string[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[1];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[arguments[0], i] = values[i - start];
+			}
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				int a1 = array.GetLength(0);
+				int a2 = array.GetLength(1);
+				for (int i = 0; i < a1; i++)
+					for (int j = 0; j < a2; j++)
+						array[i, j] = value;
+			}
+			public override object GetArray() { return array; }
+			public override void In()
+			{
+				//counter++;
+				if (array != null)
+					arrayList.Add(array);
+				array = new string[sizes[0], sizes[1]];
+				//arrayList.Add(array);
+			}
+
+			public override void Out()
+			{
+				//counter--;
+				//arrayList.RemoveAt(arrayList.Count - 1);
+				if (arrayList.Count > 0)
+				{
+					array = arrayList[arrayList.Count - 1];
+					arrayList.RemoveAt(arrayList.Count - 1);
+				}
+				else
+					array = null;
+			}
+		}
+
+		private sealed class PrivateStr3DVariableToken : UserDefinedVariableToken
+		{
+			public PrivateStr3DVariableToken(UserDefinedVariableData data)
+				: base(VariableCode.VARS3D, data)
+			{
+				int[] sizes = data.Lengths;
+				IsStatic = false;
+				arrayList = new List<string[, ,]>();
+			}
+			//int counter = 0;
+			readonly List<string[, ,]> arrayList;
+			string[, ,] array;
+			public override void SetDefault() { }
+
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				return array[arguments[0], arguments[1], arguments[2]];
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				array[arguments[0], arguments[1], arguments[2]] = value;
+			}
+
+			public override void SetValue(string[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[2];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[arguments[0], arguments[1], i] = values[i - start];
+			}
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				int a1 = array.GetLength(0);
+				int a2 = array.GetLength(1);
+				int a3 = array.GetLength(2);
+				for (int i = 0; i < a1; i++)
+					for (int j = 0; j < a2; j++)
+						for (int k = 0; k < a3; k++)
+							array[i, j, k] = value;
+			}
+			public override object GetArray() { return array; }
+			public override void In()
+			{
+				//counter++;
+				if (array != null)
+					arrayList.Add(array);
+				array = new string[sizes[0], sizes[1], sizes[2]];
+				//arrayList.Add(array);
+			}
+
+			public override void Out()
+			{
+				//counter--;
+				//arrayList.RemoveAt(arrayList.Count - 1);
+				if (arrayList.Count > 0)
+				{
+					array = arrayList[arrayList.Count - 1];
+					arrayList.RemoveAt(arrayList.Count - 1);
+				}
+				else
+					array = null;
+			}
+		}
+
+
+		#endregion
+		#region ref
+		//1808beta009で追加
+		/// <summary>
+		/// public staticとprivate dynamicをクラスレベルでは区別しない
+		/// 1808beta009時点ではprivate dynamicのみ
+		/// </summary>
+		private sealed class ReferenceInt1DToken : ReferenceToken
+		{
+			public ReferenceInt1DToken(UserDefinedVariableData data)
+				: base(VariableCode.REF, data)
+			{
+				CanRestructure = false;
+				IsStatic = !data.Private;
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				return ((Int64[])array)[arguments[0]];
+			}
+
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				((Int64[])array)[arguments[0]] = value;
+			}
+
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				int start = (int)arguments[0];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					((Int64[])array)[i] = values[i - start];
+			}
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				for (int i = start; i < end; i++)
+					((Int64[])array)[i] = value;
+			}
+
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				((Int64[])array)[arguments[0]] += value;
+				return ((Int64[])array)[arguments[0]];
+			}
+
+		}
+
+		private sealed class ReferenceInt2DToken : ReferenceToken
+		{
+			public ReferenceInt2DToken(UserDefinedVariableData data)
+				: base(VariableCode.REF2D, data)
+			{
+				CanRestructure = false;
+				IsStatic = !data.Private;
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				return ((Int64[,])array)[arguments[0], arguments[1]];
+			}
+
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				((Int64[,])array)[arguments[0], arguments[1]] = value;
+			}
+
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[2];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					((Int64[,])array)[arguments[0], i] = values[i - start];
+			}
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				int a1 = array.GetLength(0);
+				int a2 = array.GetLength(1);
+				for (int i = 0; i < a1; i++)
+					for (int j = 0; j < a2; j++)
+						((Int64[,])array)[i, j] = value;
+			}
+
+
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				((Int64[,])array)[arguments[0], arguments[1]] += value;
+				return ((Int64[,])array)[arguments[0], arguments[1]];
+			}
+		}
+
+		private sealed class ReferenceInt3DToken : ReferenceToken
+		{
+			public ReferenceInt3DToken(UserDefinedVariableData data)
+				: base(VariableCode.REF3D, data)
+			{
+				CanRestructure = false;
+				IsStatic = !data.Private;
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				return ((Int64[, ,])array)[arguments[0], arguments[1], arguments[2]];
+			}
+
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				((Int64[, ,])array)[arguments[0], arguments[1], arguments[2]] = value;
+			}
+
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[2];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					((Int64[, ,])array)[arguments[0], arguments[1], i] = values[i - start];
+			}
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				int a1 = array.GetLength(0);
+				int a2 = array.GetLength(1);
+				int a3 = array.GetLength(2);
+				for (int i = 0; i < a1; i++)
+					for (int j = 0; j < a2; j++)
+						for (int k = 0; k < a3; k++)
+							((Int64[, ,])array)[i, j, k] = value;
+			}
+
+
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				((Int64[, ,])array)[arguments[0], arguments[1], arguments[2]] += value;
+				return ((Int64[, ,])array)[arguments[0], arguments[1], arguments[2]];
+			}
+
+		}
+		private sealed class ReferenceStr1DToken : ReferenceToken
+		{
+			public ReferenceStr1DToken(UserDefinedVariableData data)
+				: base(VariableCode.REFS, data)
+			{
+				CanRestructure = false;
+				IsStatic = !data.Private;
+			}
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				return ((string[])array)[arguments[0]];
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				((string[])array)[arguments[0]] = value;
+			}
+
+			public override void SetValue(string[] values, Int64[] arguments)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				int start = (int)arguments[0];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					((string[])array)[i] = values[i - start];
+			}
+
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				for (int i = start; i < end; i++)
+					((string[])array)[i] = value;
+			}
+		}
+
+		private sealed class ReferenceStr2DToken : ReferenceToken
+		{
+			public ReferenceStr2DToken(UserDefinedVariableData data)
+				: base(VariableCode.REFS2D, data)
+			{
+				CanRestructure = false;
+				IsStatic = !data.Private;
+			}
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				return ((string[,])array)[arguments[0], arguments[1]];
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				((string[,])array)[arguments[0], arguments[1]] = value;
+			}
+
+			public override void SetValue(string[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[2];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					((string[,])array)[arguments[0], i] = values[i - start];
+			}
+
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				int a1 = array.GetLength(0);
+				int a2 = array.GetLength(1);
+				for (int i = 0; i < a1; i++)
+					for (int j = 0; j < a2; j++)
+						((string[,])array)[i, j] = value;
+			}
+		}
+
+		private sealed class ReferenceStr3DToken : ReferenceToken
+		{
+			public ReferenceStr3DToken(UserDefinedVariableData data)
+				: base(VariableCode.REFS3D, data)
+			{
+				CanRestructure = false;
+				IsStatic = !data.Private;
+			}
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				return ((string[, ,])array)[arguments[0], arguments[1], arguments[2]];
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				if (array == null)
+					throw new CodeEE("参照型変数" + varName + "は何も参照していません");
+				((string[, ,])array)[arguments[0], arguments[1], arguments[2]] = value;
+			}
+
+			public override void SetValue(string[] values, Int64[] arguments)
+			{
+				int start = (int)arguments[2];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					((string[, ,])array)[arguments[0], arguments[1], i] = values[i - start];
+			}
+
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				int a1 = array.GetLength(0);
+				int a2 = array.GetLength(1);
+				int a3 = array.GetLength(2);
+				for (int i = 0; i < a1; i++)
+					for (int j = 0; j < a2; j++)
+						for (int k = 0; k < a3; k++)
+							((string[, ,])array)[i, j, k] = value;
+			}
+
+		}
+		#endregion
+		#region chara (広域のみ)
+
+		private sealed class UserDefinedCharaInt1DVariableToken : UserDefinedCharaVariableToken
+		{
+			public UserDefinedCharaInt1DVariableToken(UserDefinedVariableData data, VariableData varData, int arrayIndex)
+				: base(VariableCode.CVAR, data, varData, arrayIndex)
+			{
+			}
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				Int64[] array = (Int64[])GetArrayChara((int)arguments[0]);
+				return array[arguments[1]];
+			}
+
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				Int64[] array = (Int64[])GetArrayChara((int)arguments[0]);
+				array[arguments[1]] = value;
+			}
+
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{
+				Int64[] array = (Int64[])GetArrayChara((int)arguments[0]);
+				int start = (int)arguments[1];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[i] = values[i - start];
+			}
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				Int64[] array = (Int64[])GetArrayChara(charaPos);
+				for (int i = start; i < end; i++)
+					array[i] = value;
+			}
+
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				Int64[] array = (Int64[])GetArrayChara((int)arguments[0]);
+				array[arguments[1]] += value;
+				return array[arguments[1]];
+			}
+		}
+
+		private sealed class UserDefinedCharaStr1DVariableToken : UserDefinedCharaVariableToken
+		{
+			public UserDefinedCharaStr1DVariableToken(UserDefinedVariableData data, VariableData varData, int arrayIndex)
+				: base(VariableCode.CVARS, data, varData, arrayIndex)
+			{
+			}
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				string[] array = (string[])GetArrayChara((int)arguments[0]);
+				return array[arguments[1]];
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				string[] array = (string[])GetArrayChara((int)arguments[0]);
+				array[arguments[1]] = value;
+			}
+
+			public override void SetValue(string[] values, Int64[] arguments)
+			{
+				string[] array = (string[])GetArrayChara((int)arguments[0]);
+				int start = (int)arguments[1];
+				int end = start + values.Length;
+				for (int i = start; i < end; i++)
+					array[i] = values[i - start];
+			}
+
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				string[] array = (string[])GetArrayChara(charaPos);
+				for (int i = start; i < end; i++)
+					array[i] = value;
+			}
+		}
+
+		private sealed class UserDefinedCharaInt2DVariableToken : UserDefinedCharaVariableToken
+		{
+			public UserDefinedCharaInt2DVariableToken(UserDefinedVariableData data, VariableData varData, int arrayIndex)
+				: base(VariableCode.CVAR2D, data, varData, arrayIndex)
+			{
+			}
+
+			public override Int64 GetIntValue(ExpressionMediator exm, Int64[] arguments)
+			{
+				Int64[,] array = (Int64[,])GetArrayChara((int)arguments[0]);
+				return array[arguments[1], arguments[2]];
+			}
+
+			public override void SetValue(Int64 value, Int64[] arguments)
+			{
+				Int64[,] array = (Int64[,])GetArrayChara((int)arguments[0]);
+				array[arguments[1], arguments[2]] = value;
+			}
+
+			public override void SetValue(Int64[] values, Int64[] arguments)
+			{
+				Int64[,] array = (Int64[,])GetArrayChara((int)arguments[0]);
+				int start = (int)arguments[2];
+				int end = start + values.Length;
+				int index1 = (int)arguments[1];
+				for (int i = start; i < end; i++)
+					array[index1, i] = values[i - start];
+			}
+
+			public override void SetValueAll(long value, int start, int end, int charaPos)
+			{
+				Int64[,] array = (Int64[,])GetArrayChara(charaPos);
+				int a1 = sizes[0];
+				int a2 = sizes[1];
+				for (int i = 0; i < a1; i++)
+					for (int j = 0; j < a2; j++)
+						array[i, j] = value;
+			}
+
+			public override Int64 PlusValue(Int64 value, Int64[] arguments)
+			{
+				Int64[,] array = (Int64[,])GetArrayChara((int)arguments[0]);
+				array[arguments[1], arguments[2]] += value;
+				return array[arguments[1], arguments[2]];
+			}
+		}
+
+		private sealed class UserDefinedCharaStr2DVariableToken : UserDefinedCharaVariableToken
+		{
+			public UserDefinedCharaStr2DVariableToken(UserDefinedVariableData data, VariableData varData, int arrayIndex)
+				: base(VariableCode.CVARS2D, data, varData, arrayIndex)
+			{
+			}
+
+			public override string GetStrValue(ExpressionMediator exm, Int64[] arguments, bool translate = false)
+			{
+				string[,] array = (string[,])GetArrayChara((int)arguments[0]);
+				return array[arguments[1], arguments[2]];
+			}
+
+			public override void SetValue(string value, Int64[] arguments)
+			{
+				string[,] array = (string[,])GetArrayChara((int)arguments[0]);
+				array[arguments[1], arguments[2]] = value;
+			}
+
+			public override void SetValue(string[] values, Int64[] arguments)
+			{
+				string[,] array = (string[,])GetArrayChara((int)arguments[0]);
+				int start = (int)arguments[2];
+				int end = start + values.Length;
+				int index1 = (int)arguments[1];
+				for (int i = start; i < end; i++)
+					array[index1, i] = values[i - start];
+			}
+
+			public override void SetValueAll(string value, int start, int end, int charaPos)
+			{
+				string[,] array = (string[,])GetArrayChara(charaPos);
+				int a1 = sizes[0];
+				int a2 = sizes[1];
+				for (int i = 0; i < a1; i++)
+					for (int j = 0; j < a2; j++)
+						array[i, j] = value;
+			}
+
+		}
+		#endregion
+		#endregion
+	}
+}

+ 1445 - 0
NTERA/Game/GameProc/ErbLoader.cs

@@ -0,0 +1,1445 @@
+using System;
+using System.Collections.Generic;
+using System.Media;
+using System.Windows.Forms;
+using Microsoft.VisualBasic;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.GameProc.Function;
+using MinorShift.Emuera.Sub;
+using MinorShift._Library;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera.GameProc
+{
+	internal sealed class ErbLoader
+	{
+		public ErbLoader(IConsole main, ExpressionMediator exm, Process proc)
+		{
+			output = main;
+			parentProcess = proc;
+			this.exm = exm;
+		}
+		readonly Process parentProcess;
+		readonly ExpressionMediator exm;
+		readonly IConsole output;
+		List<string> ignoredFNFWarningFileList = new List<string>();
+		int ignoredFNFWarningCount;
+
+		int enabledLineCount;
+		LabelDictionary labelDic;
+
+		bool noError = true;
+
+	    /// <summary>
+	    /// 複数のファイルを読む
+	    /// </summary>
+	    /// <param name="erbDir"></param>
+	    /// <param name="displayReport"></param>
+	    /// <param name="labelDictionary"></param>
+	    public bool LoadErbFiles(string erbDir, bool displayReport, LabelDictionary labelDictionary)
+		{
+			//1.713 labelDicをnewする位置を変更。
+			//checkScript();の時点でExpressionPerserがProcess.instance.LabelDicを必要とするから。
+			labelDic = labelDictionary;
+			labelDic.Initialized = false;
+			List<KeyValuePair<string, string>> erbFiles = Config.GetFiles(erbDir, "*.ERB");
+            List<string> isOnlyEvent = new List<string>();
+            noError = true;
+			uint starttime = WinmmTimer.TickCount;
+			try
+			{
+				labelDic.RemoveAll();
+				for (int i = 0; i < erbFiles.Count; i++)
+				{
+					string filename = erbFiles[i].Key;
+					string file = erbFiles[i].Value;
+#if DEBUG
+					if (displayReport)
+						output.PrintSystemLine("Elapsed time: " + (WinmmTimer.TickCount - starttime).ToString("D4") + "ms:" + filename + " is being loaded...");
+#else
+					if (displayReport)
+						output.PrintSystemLine("Loading " + filename + "...");
+#endif
+					Application.DoEvents();
+					loadErb(file, filename, isOnlyEvent);
+				}
+				ParserMediator.FlushWarningList();
+#if DEBUG
+				output.PrintSystemLine("Elapsed time: " + (WinmmTimer.TickCount - starttime).ToString("D4") + "ms:");
+#endif
+				if (displayReport)
+					output.PrintSystemLine("Building a list of user-defined functions...");
+				setLabelsArg();
+				ParserMediator.FlushWarningList();
+				labelDic.Initialized = true;
+#if DEBUG
+				output.PrintSystemLine("Elapsed time: " + (WinmmTimer.TickCount - starttime).ToString("D4") + "ms:");
+#endif
+				if (displayReport)
+					output.PrintSystemLine("Script syntax checking...");
+				checkScript();
+				ParserMediator.FlushWarningList();
+
+#if DEBUG
+				output.PrintSystemLine("Elapsed time: " + (WinmmTimer.TickCount - starttime).ToString("D4") + "ms:");
+#endif
+				if (displayReport)
+					output.PrintSystemLine("Load is complete");
+			}
+			catch (Exception e)
+			{
+				ParserMediator.FlushWarningList();
+				SystemSounds.Hand.Play();
+				output.PrintError("An unexpected error has occurred: " + Program.ExeName);
+				output.PrintError(e.GetType() + ":" + e.Message);
+				return false;
+			}
+			finally
+			{
+				parentProcess.scaningLine = null;
+			}
+            isOnlyEvent.Clear();
+			return noError;
+		}
+
+		/// <summary>
+		/// 指定されたファイルを読み込む
+		/// </summary>
+		/// <param name="filename"></param>
+		public bool LoadErbs(List<string> path, LabelDictionary labelDictionary)
+		{
+		    var isOnlyEvent = new List<string>();
+            noError = true;
+			labelDic = labelDictionary;
+			labelDic.Initialized = false;
+			foreach (string fpath in path)
+			{
+			    string fname;
+			    if (fpath.StartsWith(Program.ErbDir, Config.SCIgnoreCase) && !Program.AnalysisMode)
+					fname = fpath.Substring(Program.ErbDir.Length);
+				else
+					fname = fpath;
+				if (Program.AnalysisMode)
+					output.PrintSystemLine("Loading " + fname + "...");
+				Application.DoEvents();
+                loadErb(fpath, fname, isOnlyEvent);
+			}
+            if (Program.AnalysisMode)
+                output.NewLine();
+            ParserMediator.FlushWarningList();
+			setLabelsArg();
+			ParserMediator.FlushWarningList();
+			labelDic.Initialized = true;
+            checkScript();
+			ParserMediator.FlushWarningList();
+			parentProcess.scaningLine = null;
+            isOnlyEvent.Clear();
+            return noError;
+		}
+
+		private sealed class PPState
+		{
+			bool skip;
+			bool done;
+			public bool Disabled;
+		    readonly Stack<bool> disabledStack = new Stack<bool>();
+			Stack<bool> doneStack = new Stack<bool>();
+			Stack<string> ppMatch = new Stack<string>();
+
+			internal void AddKeyWord(string token, string token2, ScriptPosition position)
+			{
+				bool token2enabled = string.IsNullOrEmpty(token2);
+				switch (token)
+				{
+					case "SKIPSTART":
+						if (!string.IsNullOrEmpty(token2))
+						{
+							ParserMediator.Warn("There\'s an extra argument in " + token, position, 1);
+							break;
+						}
+						if (skip)
+						{
+							ParserMediator.Warn("[SKIPSTART] is being used twice or overlapping", position, 1);
+							break;
+						}
+						ppMatch.Push("SKIPEND");
+						disabledStack.Push(Disabled);
+						doneStack.Push(done);
+						skip = true;
+						Disabled = true;
+						done = false;
+						break;
+					case "IF_DEBUG":
+						if (!string.IsNullOrEmpty(token2))
+						{
+							ParserMediator.Warn("There\'s an extra argument in " + token, position, 1);
+							break;
+						}
+						ppMatch.Push("ELSEIF");
+						disabledStack.Push(Disabled);
+						doneStack.Push(done);
+						Disabled = !Program.DebugMode;
+						done = !Disabled;
+						break;
+					case "IF_NDEBUG":
+						if (!string.IsNullOrEmpty(token2))
+						{
+							ParserMediator.Warn("There\'s an extra argument in " + token, position, 1);
+							break;
+						}
+						ppMatch.Push("ELSEIF");
+						disabledStack.Push(Disabled);
+						doneStack.Push(done);
+						Disabled = Program.DebugMode;
+						done = !Disabled;
+						break;
+					case "IF":
+						if (string.IsNullOrEmpty(token2))
+						{
+							ParserMediator.Warn("Argument is missing in " + token, position, 1);
+							break;
+						}
+						ppMatch.Push("ELSEIF");
+						disabledStack.Push(Disabled);
+						doneStack.Push(done);
+						Disabled = GlobalStatic.IdentifierDictionary.GetMacro(token2) == null;
+						done = !Disabled;
+						break;
+					case "ELSEIF":
+						if (string.IsNullOrEmpty(token2))
+						{
+							ParserMediator.Warn("Argument is missing in " + token, position, 1);
+							break;
+						}
+						if (ppMatch.Count == 0 || ppMatch.Pop() != "ELSEIF")
+						{
+							ParserMediator.Warn("Inappropriate [ELSEIF] detected", position, 1);
+							break;
+						}
+						ppMatch.Push("ELSEIF");
+						Disabled = done || (GlobalStatic.IdentifierDictionary.GetMacro(token2) == null);
+						done |= !Disabled;
+						break;
+					case "ELSE":
+						if (!string.IsNullOrEmpty(token2))
+						{
+							ParserMediator.Warn("There\'s an extra argument in " + token, position, 1);
+							break;
+						}
+						if (ppMatch.Count == 0 || ppMatch.Pop() != "ELSEIF")
+						{
+							ParserMediator.Warn("Inappropriate [ELSE] detected", position, 1);
+							break;
+						}
+						ppMatch.Push("ENDIF");
+						Disabled = done;
+						done = true;
+						break;
+
+					case "SKIPEND":
+						{
+							if (!string.IsNullOrEmpty(token2))
+							{
+								ParserMediator.Warn("There\'s an extra argument in " + token, position, 1);
+								break;
+							}
+							string match = ppMatch.Count == 0 ? "" : ppMatch.Pop();
+							if (match != "SKIPEND")
+							{
+								ParserMediator.Warn("[SKIPSTART] should be closed with [SKIPEND]", position, 1);
+								break;
+							}
+							skip = false;
+							Disabled = disabledStack.Pop();
+							done = doneStack.Pop();
+						}
+						break;
+					case "ENDIF":
+						{
+							if (!string.IsNullOrEmpty(token2))
+							{
+								ParserMediator.Warn("There\'s an extra argument in " + token, position, 1);
+								break;
+							}
+							string match = ppMatch.Count == 0 ? "" : ppMatch.Pop();
+							if (match != "ENDIF" && match != "ELSEIF")
+							{
+								ParserMediator.Warn("[IF] doesn\'t have a corresponding [ENDIF]", position, 1);
+								break;
+							}
+							Disabled = disabledStack.Pop();
+							done = doneStack.Pop();
+						}
+						break;
+					default:
+						ParserMediator.Warn("An unrecognized preprocessor", position, 1);
+						break;
+				}
+				if (skip)
+					Disabled = true;
+			}
+
+			internal void FileEnd(ScriptPosition position)
+			{
+				if (ppMatch.Count != 0)
+				{
+					string match = ppMatch.Pop();
+					if (match == "ELSEIF")
+						match = "ENDIF";
+					ParserMediator.Warn("[" + match + "]がありません", position, 1);
+				}
+			}
+		}
+
+		/// <summary>
+		/// ファイル一つを読む
+		/// </summary>
+		/// <param name="filepath"></param>
+		private void loadErb(string filepath, string filename, List<string> isOnlyEvent)
+		{
+			//読み込んだファイルのパスを記録
+			//一部ファイルの再読み込み時の処理用
+			labelDic.AddFilename(filename);
+			EraStreamReader eReader = new EraStreamReader(Config.UseRenameFile && ParserMediator.RenameDic != null);
+			if (!eReader.Open(filepath, filename))
+			{
+				output.PrintError("Failed to open " + eReader.Filename);
+				return;
+			}
+			try
+			{
+				PPState ppstate = new PPState();
+				LogicalLine nextLine = new NullLine();
+				LogicalLine lastLine = new NullLine();
+				FunctionLabelLine lastLabelLine = null;
+				StringStream st = null;
+				string rowLine = null;
+				ScriptPosition position = null;
+				int funcCount = 0;
+				if (Program.AnalysisMode)
+					output.PrintSystemLine(" ");
+				while ((st = eReader.ReadEnabledLine()) != null)
+				{
+					rowLine = st.RowString;
+					position = new ScriptPosition(eReader.Filename, eReader.LineNo, rowLine);
+					//rename処理をEraStreamReaderに移管
+					//変換できなかった[[~~]]についてはLexAnalyzerがエラーを投げる
+					if (st.Current == '[' && st.Next != '[')
+					{
+						st.ShiftNext();
+						string token = LexicalAnalyzer.ReadSingleIdentifier(st);
+						LexicalAnalyzer.SkipWhiteSpace(st);
+						string token2 = LexicalAnalyzer.ReadSingleIdentifier(st);
+						if ((string.IsNullOrEmpty(token)) || (st.Current != ']'))
+							ParserMediator.Warn("Illegal use of []", position, 1);
+						ppstate.AddKeyWord(token, token2, position);
+						st.ShiftNext();
+						if (!st.EOS)
+							ParserMediator.Warn("[" + token + "]の後ろは無視されます。", position, 1);
+						continue;
+					}
+					//if ((skip) || (Program.DebugMode && ifndebug) || (!Program.DebugMode && ifdebug))
+					//	continue;
+					if (ppstate.Disabled)
+						continue;
+					//ここまでプリプロセッサ
+
+					if (st.Current == '#')
+					{
+						if ((lastLine == null) || !(lastLine is FunctionLabelLine))
+						{
+							ParserMediator.Warn("関数宣言の直後以外で#行が使われています", position, 1);
+							continue;
+						}
+						if (!LogicalLineParser.ParseSharpLine((FunctionLabelLine)lastLine, st, position, isOnlyEvent))
+							noError = false;
+						continue;
+					}
+					if ((st.Current == '$') || (st.Current == '@'))
+					{
+						bool isFunction = (st.Current == '@');
+						nextLine = LogicalLineParser.ParseLabelLine(st, position, output);
+						if (isFunction)
+						{
+							FunctionLabelLine label = (FunctionLabelLine)nextLine;
+							lastLabelLine = label;
+							if (label is InvalidLabelLine)
+							{
+								noError = false;
+								ParserMediator.Warn(nextLine.ErrMes, position, 2);
+								labelDic.AddInvalidLabel(label);
+							}
+							else// if (label is FunctionLabelLine)
+							{
+								labelDic.AddLabel(label);
+								if (!label.IsEvent && (Config.WarnNormalFunctionOverloading || Program.AnalysisMode))
+								{
+									FunctionLabelLine seniorLabel = labelDic.GetSameNameLabel(label);
+                                    if (seniorLabel != null)
+                                    {
+                                        //output.NewLine();
+                                        ParserMediator.Warn("関数@" + label.LabelName + "は既に定義(" + seniorLabel.Position.Filename + "の" + seniorLabel.Position.LineNo + "行目)されています", position, 1);
+                                        funcCount = -1;
+                                    }
+								}
+								funcCount++;
+								if (Program.AnalysisMode && (Config.PrintCPerLine > 0 && (funcCount % Config.PrintCPerLine) == 0))
+								{
+									output.NewLine();
+									output.PrintSystemLine(" ");
+								}
+							}
+						}
+						else
+						{
+							if (nextLine is GotoLabelLine)
+							{
+								GotoLabelLine gotoLabel = (GotoLabelLine)nextLine;
+								gotoLabel.ParentLabelLine = lastLabelLine;
+								if (lastLabelLine != null && !labelDic.AddLabelDollar(gotoLabel))
+								{
+									ScriptPosition pos = labelDic.GetLabelDollar(gotoLabel.LabelName, lastLabelLine).Position;
+									ParserMediator.Warn("ラベル名$" + gotoLabel.LabelName + "は既に同じ関数内(" + pos.Filename + "の" + pos.LineNo + "行目)で使用されています", position, 2);
+								}
+							}
+						}
+						if (nextLine is InvalidLine)
+						{
+							noError = false;
+							ParserMediator.Warn(nextLine.ErrMes, position, 2);
+						}
+					}
+					else
+					{
+						//1808alpha006 処理位置変更
+                        ////全置換はここで対応
+                        ////1756beta1+++ 最初に全置換してしまうと関数定義を_Renameでとか論外なことができてしまうので永久封印した
+                        //if (ParserMediator.RenameDic != null && st.CurrentEqualTo("[[") && (rowLine.TrimEnd().IndexOf("]]") == rowLine.TrimEnd().Length - 2))
+                        //{
+                        //    string replacedLine = st.Substring();
+                        //    foreach (KeyValuePair<string, string> pair in ParserMediator.RenameDic)
+                        //        replacedLine = replacedLine.Replace(pair.Key, pair.Value);
+                        //    st = new StringStream(replacedLine);
+                        //}
+                        nextLine = LogicalLineParser.ParseLine(st, position, output);
+						if (nextLine == null)
+							continue;
+						if (nextLine is InvalidLine)
+						{
+							noError = false;
+                            ParserMediator.Warn(nextLine.ErrMes, position, 2);
+						}
+					}
+					if (lastLabelLine == null)
+						ParserMediator.Warn("関数が定義されるより前に行があります", position, 1);
+					nextLine.ParentLabelLine = lastLabelLine;
+					lastLine = addLine(nextLine, lastLine);
+				}
+				addLine(new NullLine(), lastLine);
+				position = new ScriptPosition(eReader.Filename, -1, null);
+				ppstate.FileEnd(position);
+			}
+			finally
+			{
+				eReader.Close();
+			}
+		}
+		
+		private LogicalLine addLine(LogicalLine nextLine, LogicalLine lastLine)
+		{
+			if (nextLine == null)
+				return null;
+			enabledLineCount++;
+			lastLine.NextLine = nextLine;
+			return nextLine;
+		}
+
+		private void setLabelsArg()
+		{
+			List<FunctionLabelLine> labelList = labelDic.GetAllLabels(false);
+			foreach (FunctionLabelLine label in labelList)
+			{
+				try
+				{
+					if (label.Arg != null)
+						continue;
+					parentProcess.scaningLine = label;
+					parseLabel(label);
+				}
+				catch (Exception exc)
+				{
+					SystemSounds.Hand.Play();
+					string errmes = exc.Message;
+					if (!(exc is EmueraException))
+						errmes = exc.GetType() + ":" + errmes;
+					ParserMediator.Warn("関数@" + label.LabelName + " の引数のエラー:" + errmes, label, 2, true, false);
+					label.ErrMes = "ロード時に解析に失敗した関数が呼び出されました";
+                    label.IsError = true;
+				}
+				finally
+				{
+					parentProcess.scaningLine = null;
+				}
+			}
+			labelDic.SortLabels();
+		}
+
+		private void parseLabel(FunctionLabelLine label)
+		{
+			WordCollection wc = label.PopRowArgs();
+			string errMes = null;
+			SingleTerm[] subNames = new SingleTerm[0];
+			VariableTerm[] args = new VariableTerm[0];
+			SingleTerm[] defs = new SingleTerm[0];
+			int maxArg = -1;
+			int maxArgs = -1;
+			//1807 非イベント関数のシステム関数については警告レベル低下&エラー解除&引数を設定するように。
+			if (label.IsEvent)
+			{
+				if (!wc.EOL)
+					ParserMediator.Warn("イベント関数@" + label.LabelName + " に引数は設定できません", label, 2, true, false);
+				//label.SubNames = subNames;
+				label.Arg = args;
+				label.Def = defs;
+				label.ArgLength = -1;
+				label.ArgsLength = -1;
+				return;
+			}
+
+			if (!wc.EOL)
+			{
+				if (label.IsSystem)
+					ParserMediator.Warn("システム関数@" + label.LabelName + " に引数が設定されています", label, 1, false, false);
+				SymbolWord symbol = wc.Current as SymbolWord;
+				wc.ShiftNext();
+				if (symbol == null)
+				{ errMes = "引数の書式が間違っています"; goto err; }
+				if (symbol.Type == '[')//TODO:subNames 結局実装しないかも
+				{
+					IOperandTerm[] subNamesRow = ExpressionParser.ReduceArguments(wc, ArgsEndWith.RightBracket, false);
+					if (subNamesRow.Length == 0)
+					{ errMes = "関数定義の[]内の引数は空にできません"; goto err; }
+					subNames = new SingleTerm[subNamesRow.Length];
+					for (int i = 0; i < subNamesRow.Length; i++)
+					{
+						if (subNamesRow[i] == null)
+						{ errMes = "関数定義の引数は省略できません"; goto err; }
+						IOperandTerm term = subNamesRow[i].Restructure(exm);
+						subNames[i] = term as SingleTerm;
+						if (subNames[i] == null)
+						{ errMes = "関数定義の[]内の引数は定数のみ指定できます"; goto err; }
+					}
+					symbol = wc.Current as SymbolWord;
+					if ((!wc.EOL) && (symbol == null))
+					{ errMes = "引数の書式が間違っています"; goto err; }
+					wc.ShiftNext();
+				}
+				if (!wc.EOL)
+				{
+					IOperandTerm[] argsRow = null;
+                    if (symbol.Type == ',')
+						argsRow = ExpressionParser.ReduceArguments(wc, ArgsEndWith.EoL, true);
+					else if (symbol.Type == '(')
+						argsRow = ExpressionParser.ReduceArguments(wc, ArgsEndWith.RightParenthesis, true);
+					else
+					{ errMes = "引数の書式が間違っています"; goto err; }
+					int length = argsRow.Length / 2;
+					args = new VariableTerm[length];
+                    defs = new SingleTerm[length];
+					for (int i = 0; i < length; i++)
+					{
+						VariableTerm vTerm = null;
+						SingleTerm def = null;
+						IOperandTerm term = argsRow[i * 2];
+                        //引数読み取り時点で判別されないといけない
+                        //if (term == null)
+                        //{ errMes = "関数定義の引数は省略できません"; goto err; }
+						vTerm = term.Restructure(exm) as VariableTerm;
+						if ((vTerm == null) || (vTerm.Identifier.IsConst))
+						{ errMes = "関数定義の引数には代入可能な変数を指定してください"; goto err; }
+
+						if (!vTerm.Identifier.IsReference)//参照型なら添え字不要
+						{
+							if (vTerm is VariableNoArgTerm)
+							{ errMes = "関数定義の参照型でない引数\"" + vTerm.Identifier.Name + "\"に添え字が指定されていません"; goto err; }
+							if (!vTerm.isAllConst)
+							{ errMes = "関数定義の引数の添え字には定数を指定してください"; goto err; }
+						}
+						for (int j = 0; j < i; j++)
+                        {
+                            if (vTerm.checkSameTerm(args[j]))
+                                ParserMediator.Warn("第" +  Strings.StrConv((i + 1).ToString(), VbStrConv.Wide, Config.Language) + "引数\"" + vTerm.GetFullString() + "\"はすでに第" + Strings.StrConv((j + 1).ToString(), VbStrConv.Wide, Config.Language) + "引数として宣言されています", label, 1, false, false);
+                        }
+						if (vTerm.Identifier.Code == VariableCode.ARG)
+						{
+							if (maxArg < vTerm.getEl1forArg + 1)
+								maxArg = vTerm.getEl1forArg + 1;
+						}
+						else if (vTerm.Identifier.Code == VariableCode.ARGS)
+						{
+							if (maxArgs < vTerm.getEl1forArg + 1)
+								maxArgs = vTerm.getEl1forArg + 1;
+						}
+						bool canDef = (vTerm.Identifier.Code == VariableCode.ARG || vTerm.Identifier.Code == VariableCode.ARGS || vTerm.Identifier.IsPrivate);
+						term = argsRow[i * 2 + 1];
+						if (term is NullTerm)
+						{
+							if (canDef)// && label.ArgOptional)
+							{
+								if (vTerm.GetOperandType() == typeof(Int64))
+									def = new SingleTerm(0);
+								else
+									def = new SingleTerm("");
+							}
+						}
+						else
+						{
+							def = term.Restructure(exm) as SingleTerm;
+							if (def == null)
+							{ errMes = "引数の初期値には定数のみを指定できます"; goto err; }
+							if (!canDef)
+							{ errMes = "引数の初期値を定義できるのは\"ARG\"、\"ARGS\"またはプライベート変数のみです"; goto err; }
+
+							if (vTerm.Identifier.IsReference)
+							{ errMes = "参照渡しの引数に初期値は定義できません"; goto err; }
+							if (vTerm.GetOperandType() != def.GetOperandType())
+							{ errMes = "引数の型と初期値の型が一致していません"; goto err; }
+						}
+						args[i] = vTerm;
+						defs[i] = def;
+					}
+
+				}
+			}
+			if (!wc.EOL)
+			{ errMes = "引数の書式が間違っています"; goto err; }
+
+            //label.SubNames = subNames;
+			label.Arg = args;
+			label.Def = defs;
+			label.ArgLength = maxArg;
+			label.ArgsLength = maxArgs;
+			return;
+		err:
+			ParserMediator.Warn("関数@" + label.LabelName + " の引数のエラー:" + errMes, label, 2, true, false);
+		}
+
+
+		public bool useCallForm;
+		/// <summary>
+		/// 読込終わったファイルをチェックする
+		/// </summary>
+		private void checkScript()
+		{
+			int usedLabelCount = 0;
+			int labelDepth = -1;
+			List<FunctionLabelLine> labelList = labelDic.GetAllLabels(true);
+
+			while (true)
+			{
+				labelDepth++;
+				int countInDepth = 0;
+				foreach (FunctionLabelLine label in labelList)
+				{
+					if (label.Depth != labelDepth)
+						continue;
+					//1756beta003 なんで追加したんだろう デバグ中になんかやったのか とりあえずコメントアウトしておく
+					//if (label.LabelName == "EVENTTURNEND")
+					//    useCallForm = true;
+					usedLabelCount++;
+					countInDepth++;
+					checkFunctionWithCatch(label);
+				}
+				if (countInDepth == 0)
+					break;
+			}
+            labelDepth = -1;
+			List<string> ignoredFNCWarningFileList = new List<string>();
+			int ignoredFNCWarningCount = 0;
+
+			bool ignoreAll = false;
+			DisplayWarningFlag notCalledWarning = Config.FunctionNotCalledWarning;
+			switch (notCalledWarning)
+			{
+				case DisplayWarningFlag.IGNORE:
+				case DisplayWarningFlag.LATER:
+					ignoreAll = true;
+					break;
+			}
+			if (useCallForm)
+			{//callform系が使われたら全ての関数が呼び出されたとみなす。
+                if (Program.AnalysisMode)
+					output.PrintSystemLine("CALLFORM系命令が使われたため、呼び出されない関数のチェックは行われません。");
+				foreach (FunctionLabelLine label in labelList)
+				{
+					if (label.Depth != labelDepth)
+						continue;
+					checkFunctionWithCatch(label);
+				}
+			}
+			else
+			{
+				bool ignoreUncalledFunction = Config.IgnoreUncalledFunction;
+				foreach (FunctionLabelLine label in labelList)
+				{
+					if (label.Depth != labelDepth)
+						continue;
+                    //解析モード時は呼ばれなかったものをここで解析
+                    if (Program.AnalysisMode)
+                        checkFunctionWithCatch(label);
+					bool ignore = false;
+					if (notCalledWarning == DisplayWarningFlag.ONCE)
+					{
+						string filename = label.Position.Filename.ToUpper();
+
+						if (!string.IsNullOrEmpty(filename))
+						{
+							if (ignoredFNCWarningFileList.Contains(filename))
+							{
+								ignore = true;
+							}
+							else
+							{
+								ignore = false;
+								ignoredFNCWarningFileList.Add(filename);
+							}
+						}
+                        //break;
+					}
+					if (ignoreAll || ignore)
+						ignoredFNCWarningCount++;
+					else
+						ParserMediator.Warn("関数@" + label.LabelName + "は定義されていますが一度も呼び出されません", label, 1, false, false);
+					if (!ignoreUncalledFunction)
+						checkFunctionWithCatch(label);
+					else
+					{
+						if (!(label.NextLine is NullLine) && !(label.NextLine is FunctionLabelLine))
+						{
+							if (!label.NextLine.IsError)
+							{
+								label.NextLine.IsError = true;
+								label.NextLine.ErrMes = "呼び出されないはずの関数が呼ばれた";
+							}
+						}
+					}
+				}
+			}
+			if (Program.AnalysisMode && (warningDic.Keys.Count > 0 || GlobalStatic.tempDic.Keys.Count > 0))
+			{
+				output.PrintError("・定義が見つからなかった関数: 他のファイルで定義されている場合はこの警告は無視できます");
+				if (warningDic.Keys.Count > 0)
+				{
+					output.PrintError(" ○一般関数:");
+					foreach (string labelName in warningDic.Keys)
+					{
+						output.PrintError("  " + labelName + ": " + warningDic[labelName] + "回");
+					}
+				}
+				if (GlobalStatic.tempDic.Keys.Count > 0)
+				{
+					output.PrintError(" ○文中関数:");
+					foreach (string labelName in GlobalStatic.tempDic.Keys)
+					{
+						output.PrintError("  " + labelName + ": " + GlobalStatic.tempDic[labelName] + "回");
+					}
+				}
+			}
+			else
+			{
+				if ((ignoredFNCWarningCount > 0) && (Config.DisplayWarningLevel <= 1) && (notCalledWarning != DisplayWarningFlag.IGNORE))
+					output.PrintError(string.Format("警告Lv1:定義された関数が一度も呼び出されていない事に関する警告を{0}件無視しました", ignoredFNCWarningCount));
+				if ((ignoredFNFWarningCount > 0) && (Config.DisplayWarningLevel <= 2) && (notCalledWarning != DisplayWarningFlag.IGNORE))
+					output.PrintError(string.Format("警告Lv2:定義されていない関数を呼び出した事に関する警告を{0}件無視しました", ignoredFNFWarningCount));
+			}
+			ParserMediator.FlushWarningList();
+			if (Config.DisplayReport)
+				output.PrintError(string.Format("Number of non-comment lines: {0}, All functions total: {1}, Total called functions: {2}", enabledLineCount, labelDic.Count, usedLabelCount));
+			if (Config.AllowFunctionOverloading && Config.WarnFunctionOverloading)
+			{
+				List<string> overloadedList = GlobalStatic.IdentifierDictionary.GetOverloadedList(labelDic);
+				if (overloadedList.Count > 0)
+				{
+					output.NewLine();
+					output.PrintError("*****警告*****");
+					foreach (string funcname in overloadedList)
+					{
+						output.PrintSystemLine("  システム関数\"" + funcname + "\"がユーザー定義関数によって上書きされています");
+					}
+					output.PrintSystemLine("  上記の関数を利用するスクリプトは意図通りに動かない可能性があります");
+					output.NewLine();
+					output.PrintSystemLine("  ※この警告は該当する式中関数を利用しているEmuera専用スクリプト向けの警告です。");
+					output.PrintSystemLine("  eramaker用のスクリプトの動作には影響しません。");
+					output.PrintSystemLine("  今後この警告が不要ならばコンフィグの「システム関数が上書きされたとき警告を表示する」をOFFにして下さい。");
+					output.PrintSystemLine("************");
+				}
+			}
+		}
+
+
+		public Dictionary<string, Int64> warningDic = new Dictionary<string, Int64>();
+		private void printFunctionNotFoundWarning(string str, LogicalLine line, int level, bool isError)
+		{
+			if (Program.AnalysisMode)
+			{
+				if (warningDic.ContainsKey(str))
+					warningDic[str]++;
+				else
+					warningDic.Add(str, 1);
+				return;
+			}
+			if (isError)
+			{
+				line.IsError = true;
+				line.ErrMes = str;
+			}
+			if (level < Config.DisplayWarningLevel)
+				return;
+			bool ignore = false;
+			DisplayWarningFlag warnFlag = Config.FunctionNotFoundWarning;
+			if (warnFlag == DisplayWarningFlag.IGNORE)
+				ignore = true;
+			else if (warnFlag == DisplayWarningFlag.DISPLAY)
+				ignore = false;
+			else if (warnFlag == DisplayWarningFlag.ONCE)
+			{
+
+				string filename = line.Position.Filename.ToUpper();
+				if (!string.IsNullOrEmpty(filename))
+				{
+					if (ignoredFNFWarningFileList.Contains(filename))
+					{
+						ignore = true;
+					}
+					else
+					{
+						ignore = false;
+						ignoredFNFWarningFileList.Add(filename);
+					}
+				}
+			}
+			if (ignore && !Program.AnalysisMode)
+			{
+				ignoredFNFWarningCount++;
+				return;
+			}
+			ParserMediator.Warn(str, line, level, isError, false);
+		}
+
+		private void checkFunctionWithCatch(FunctionLabelLine label)
+		{//ここでエラーを捕まえることは本来はないはず。ExeEE相当。
+			try
+			{
+				Application.DoEvents();
+				string filename = label.Position.Filename.ToUpper();
+				setArgument(label);
+				nestCheck(label);
+                setJumpTo(label);
+			}
+			catch (Exception exc)
+			{
+				SystemSounds.Hand.Play();
+                //1756beta2+v6.1 修正の効率化のために何かパース関係でハンドリングできてないエラーが出た場合はスタックトレースを投げるようにした
+                string errmes = (exc is EmueraException) ? exc.Message : exc.GetType() + ":" + exc.Message;
+                ParserMediator.Warn("@" + label.LabelName + " の解析中にエラー:" + errmes, label, 2, true, false, !(exc is EmueraException) ? exc.StackTrace : null);
+                label.ErrMes = "ロード時に解析に失敗した関数が呼び出されました";
+			}
+			finally
+			{
+				parentProcess.scaningLine = null;
+			}
+
+		}
+
+		private void setArgument(FunctionLabelLine label)
+		{
+			//1周目/3周
+			//引数の解析とか
+			LogicalLine nextLine = label;
+			bool inMethod = label.IsMethod;
+			while (true)
+			{
+				nextLine = nextLine.NextLine;
+				parentProcess.scaningLine = nextLine;
+				if (!(nextLine is InstructionLine func))
+				{
+					if ((nextLine is NullLine) || (nextLine is FunctionLabelLine))
+						break;
+					continue;
+				}
+				if (inMethod)
+				{
+					if (!func.Function.IsMethodSafe())
+					{
+						ParserMediator.Warn(func.Function.Name + "命令は#FUNCTION中で使うことはできません", nextLine, 2, true, false);
+						continue;
+					}
+				}
+                if (Config.NeedReduceArgumentOnLoad || Program.AnalysisMode || func.Function.IsForceSetArg())
+                    ArgumentParser.SetArgumentTo(func);
+			}
+		}
+
+		private void nestCheck(FunctionLabelLine label)
+		{
+			//2周目/3周
+			//IF-ELSEIF-ENDIF、REPEAT-RENDの対応チェックなど
+			//PRINTDATA系もここでチェック
+			LogicalLine nextLine = label;
+			List<InstructionLine> tempLineList = new List<InstructionLine>();
+			Stack<InstructionLine> nestStack = new Stack<InstructionLine>();
+            Stack<InstructionLine> SelectcaseStack = new Stack<InstructionLine>();
+			InstructionLine pairLine = null;
+			while (true)
+			{
+				nextLine = nextLine.NextLine;
+				parentProcess.scaningLine = nextLine;
+                if ((nextLine is NullLine) || (nextLine is FunctionLabelLine))
+                    break;
+                if (!(nextLine is InstructionLine))
+                {
+                    if (nextLine is GotoLabelLine)
+                    {
+                        InstructionLine currentBaseFunc = nestStack.Count == 0 ? null : nestStack.Peek();
+                        if (currentBaseFunc != null)
+                        {
+                            if ((currentBaseFunc.FunctionCode == FunctionCode.PRINTDATA)
+                                || (currentBaseFunc.FunctionCode == FunctionCode.PRINTDATAL)
+                                || (currentBaseFunc.FunctionCode == FunctionCode.PRINTDATAW)
+                                || (currentBaseFunc.FunctionCode == FunctionCode.PRINTDATAD)
+                                || (currentBaseFunc.FunctionCode == FunctionCode.PRINTDATADL)
+                                || (currentBaseFunc.FunctionCode == FunctionCode.PRINTDATADW)
+                                || (currentBaseFunc.FunctionCode == FunctionCode.PRINTDATAK)
+                                || (currentBaseFunc.FunctionCode == FunctionCode.PRINTDATAKL)
+                                || (currentBaseFunc.FunctionCode == FunctionCode.PRINTDATAKW)
+                                || (currentBaseFunc.FunctionCode == FunctionCode.STRDATA)
+                                || (currentBaseFunc.FunctionCode == FunctionCode.DATALIST)
+                                || (currentBaseFunc.FunctionCode == FunctionCode.TRYCALLLIST)
+                                || (currentBaseFunc.FunctionCode == FunctionCode.TRYJUMPLIST)
+                                || (currentBaseFunc.FunctionCode == FunctionCode.TRYGOTOLIST))
+                                //|| (currentBaseFunc.FunctionCode == FunctionCode.SELECTCASE))
+                            {
+                                ParserMediator.Warn(currentBaseFunc.Function.Name + "構文中に$ラベルを定義することはできません", nextLine, 2, true, false);
+                            }
+                        }
+                    }
+                    continue;
+                }
+				InstructionLine func = (InstructionLine)nextLine;
+				pairLine = null;
+				InstructionLine baseFunc = nestStack.Count == 0 ? null : nestStack.Peek();
+				if (baseFunc != null)
+				{
+					if ((baseFunc.Function.IsPrintData() || baseFunc.FunctionCode == FunctionCode.STRDATA) )
+					{
+						if ((func.FunctionCode != FunctionCode.DATA) && (func.FunctionCode != FunctionCode.DATAFORM) && (func.FunctionCode != FunctionCode.DATALIST)
+							&& (func.FunctionCode != FunctionCode.ENDLIST) && (func.FunctionCode != FunctionCode.ENDDATA))
+						{
+							ParserMediator.Warn(baseFunc.Function.Name + "構文に使用できない命令\'" + func.Function.Name + "\'が含まれています", func, 2, true, false);
+							continue;
+						}
+					}
+					else if (baseFunc.FunctionCode == FunctionCode.DATALIST)
+					{
+						if ((func.FunctionCode != FunctionCode.DATA) && (func.FunctionCode != FunctionCode.DATAFORM) && (func.FunctionCode != FunctionCode.ENDLIST))
+						{
+							ParserMediator.Warn("DATALIST構文に使用できない命令\'" + func.Function.Name + "\'が含まれています", func, 2, true, false);
+							continue;
+						}
+					}
+					else if ((baseFunc.FunctionCode == FunctionCode.TRYCALLLIST) || (baseFunc.FunctionCode == FunctionCode.TRYJUMPLIST) || (baseFunc.FunctionCode == FunctionCode.TRYGOTOLIST))
+					{
+						if ((func.FunctionCode != FunctionCode.FUNC) && (func.FunctionCode != FunctionCode.ENDFUNC))
+						{
+							ParserMediator.Warn(baseFunc.Function.Name + "構文に使用できない命令\'" + func.Function.Name + "\'が含まれています", func, 2, true, false);
+							continue;
+						}
+					}
+					else if (baseFunc.FunctionCode == FunctionCode.SELECTCASE)
+					{
+						if ((baseFunc.IfCaseList.Count == 0) && (func.FunctionCode != FunctionCode.CASE) && (func.FunctionCode != FunctionCode.CASEELSE) && (func.FunctionCode != FunctionCode.ENDSELECT))
+						{
+							ParserMediator.Warn("SELECTCASE構文の分岐の外に命令\'" + func.Function.Name + "\'が含まれています", func, 2, true, false);
+							continue;
+						}
+					}
+				}
+				switch (func.FunctionCode)
+				{
+					case FunctionCode.REPEAT:
+						foreach (InstructionLine iLine in nestStack)
+						{
+							if (iLine.FunctionCode == FunctionCode.REPEAT)
+							{
+								ParserMediator.Warn("REPEAT statements cannot be nested", func, 2, true, false);
+                                break;
+							}
+						}
+						if (func.IsError)
+							break;
+						nestStack.Push(func);
+						break;
+					case FunctionCode.IF:
+						nestStack.Push(func);
+						func.IfCaseList = new List<InstructionLine>();
+						func.IfCaseList.Add(func);
+						break;
+					case FunctionCode.SELECTCASE:
+						nestStack.Push(func);
+						func.IfCaseList = new List<InstructionLine>();
+                        SelectcaseStack.Push(func);
+						break;
+					case FunctionCode.FOR:
+					case FunctionCode.WHILE:
+					case FunctionCode.TRYCGOTO:
+					case FunctionCode.TRYCJUMP:
+					case FunctionCode.TRYCCALL:
+					case FunctionCode.TRYCGOTOFORM:
+					case FunctionCode.TRYCJUMPFORM:
+					case FunctionCode.TRYCCALLFORM:
+					case FunctionCode.DO:
+						nestStack.Push(func);
+						break;
+					case FunctionCode.BREAK:
+					case FunctionCode.CONTINUE:
+						InstructionLine[] array = nestStack.ToArray();
+						for (int i = 0; i < array.Length; i++)
+						{
+							if ((array[i].FunctionCode == FunctionCode.REPEAT)
+								|| (array[i].FunctionCode == FunctionCode.FOR)
+								|| (array[i].FunctionCode == FunctionCode.WHILE)
+								|| (array[i].FunctionCode == FunctionCode.DO))
+							{
+								pairLine = array[i];
+								break;
+							}
+						}
+						if (pairLine == null)
+						{
+							ParserMediator.Warn("REPEAT, FOR, WHILE, DOの中以外で" + func.Function.Name + "文が使われました", func, 2, true, false);
+							break;
+						}
+						func.JumpTo = pairLine;
+						break;
+
+					case FunctionCode.ELSEIF:
+					case FunctionCode.ELSE:
+						{
+							//1.725 Stack<T>.Peek()はStackが空の時はnullを返す仕様だと思いこんでおりました。
+							InstructionLine ifLine = nestStack.Count == 0 ? null : nestStack.Peek();
+							if ((ifLine == null) || (ifLine.FunctionCode != FunctionCode.IF))
+							{
+								ParserMediator.Warn("IF~ENDIFの外で" + func.Function.Name + "文が使われました", func, 2, true, false);
+                                break;
+							}
+							if (ifLine.IfCaseList[ifLine.IfCaseList.Count - 1].FunctionCode == FunctionCode.ELSE)
+								ParserMediator.Warn("ELSE文より後で" + func.Function.Name + "文が使われました", func, 1, false, false);
+							ifLine.IfCaseList.Add(func);
+						}
+						break;
+					case FunctionCode.ENDIF:
+						{
+							InstructionLine ifLine = nestStack.Count == 0 ? null : nestStack.Peek();
+							if ((ifLine == null) || (ifLine.FunctionCode != FunctionCode.IF))
+							{
+								ParserMediator.Warn("対応するIFの無いENDIF文です", func, 2, true, false);
+								break;
+							}
+							foreach (InstructionLine ifelseifLine in ifLine.IfCaseList)
+							{
+								ifelseifLine.JumpTo = func;
+							}
+							nestStack.Pop();
+						}
+						break;
+					case FunctionCode.CASE:
+					case FunctionCode.CASEELSE:
+						{
+							InstructionLine selectLine = nestStack.Count == 0 ? null : nestStack.Peek();
+							if ((selectLine == null) || (selectLine.FunctionCode != FunctionCode.SELECTCASE && SelectcaseStack.Count == 0))
+							{
+								ParserMediator.Warn("SELECTCASE~ENDSELECTの外で" + func.Function.Name + "文が使われました", func, 2, true, false);
+								break;
+							}
+
+							if (selectLine.FunctionCode != FunctionCode.SELECTCASE && SelectcaseStack.Count > 0)
+							{
+								do
+								{
+									ParserMediator.Warn(selectLine.Function.Name + "文に対応する" + FunctionIdentifier.getMatchFunction(selectLine.FunctionCode) + "がない状態で" + func.Function.Name + "文に到達しました", func, 2, true, false);
+									//これを跨いでIF等が閉じられることがないようにする。
+									nestStack.Pop();
+									//if (nestStack.Count > 0) //空になってるかは下で判定できるので、これを見る必要がない
+									selectLine = nestStack.Count == 0 ? null : nestStack.Peek(); //ちなみにnullになることはない(SELECTCASEがない場合は上で弾けるから)
+								} while (selectLine != null && selectLine.FunctionCode != FunctionCode.SELECTCASE);
+								break;
+							}
+							if ((selectLine.IfCaseList.Count > 0) &&
+								(selectLine.IfCaseList[selectLine.IfCaseList.Count - 1].FunctionCode == FunctionCode.CASEELSE))
+								ParserMediator.Warn("CASEELSE文より後で" + func.Function.Name + "文が使われました", func, 1, false, false);
+							selectLine.IfCaseList.Add(func);
+						}
+						break;
+					case FunctionCode.ENDSELECT:
+						{
+							InstructionLine selectLine = nestStack.Count == 0 ? null : nestStack.Peek();
+							if ((selectLine == null) || (selectLine.FunctionCode != FunctionCode.SELECTCASE && SelectcaseStack.Count == 0))
+							{
+								ParserMediator.Warn("対応するSELECTCASEの無いENDSELECT文です", func, 2, true, false);
+                                break;
+							}
+
+							if (selectLine.FunctionCode != FunctionCode.SELECTCASE && SelectcaseStack.Count > 0)
+							{
+								do
+								{
+									ParserMediator.Warn(selectLine.Function.Name + "文に対応する" + FunctionIdentifier.getMatchFunction(selectLine.FunctionCode) + "がない状態で" + func.Function.Name + "文に到達しました", func, 2, true, false);
+									//これを跨いでIF等が閉じられることがないようにする。
+									nestStack.Pop();
+									//if (nestStack.Count > 0) //空になってるかは下で判定できるので、これを見る必要がない
+									selectLine = nestStack.Count == 0 ? null : nestStack.Peek(); //ちなみにnullになることはない(SELECTCASEがない場合は上で弾けるから)
+								} while (selectLine != null && selectLine.FunctionCode != FunctionCode.SELECTCASE); 
+								//とりあえず、対応するSELECTCASE跨ぎは閉じる
+								SelectcaseStack.Pop();
+								//こっちでも抜かないとSELECTCASEが2つのENDSELECTに対応してしまう
+								nestStack.Pop();
+								break;
+							}
+							nestStack.Pop();
+                            SelectcaseStack.Pop();
+							selectLine.JumpTo = func;
+							if (selectLine.IsError)
+								break;
+							IOperandTerm term = ((ExpressionArgument)selectLine.Argument).Term;
+							if (term == null)
+							{
+								ParserMediator.Warn("SELECTCASEの引数がありません", selectLine, 2, true, false);
+								break;
+							}
+							foreach (InstructionLine caseLine in selectLine.IfCaseList)
+							{
+								caseLine.JumpTo = func;
+								if (caseLine.IsError)
+									continue;
+								if (caseLine.FunctionCode == FunctionCode.CASEELSE)
+									continue;
+								CaseExpression[] caseExps = ((CaseArgument)caseLine.Argument).CaseExps;
+								if (caseExps.Length == 0)
+									ParserMediator.Warn("CASEの引数がありません", caseLine, 2, true, false);
+
+								foreach (CaseExpression exp in caseExps)
+								{
+									if (exp.GetOperandType() != term.GetOperandType())
+										ParserMediator.Warn("CASEの引数の型がSELECTCASEと一致しません", caseLine, 2, true, false);
+								}
+
+							}
+						}
+						break;
+					case FunctionCode.REND:
+					case FunctionCode.NEXT:
+					case FunctionCode.WEND:
+					case FunctionCode.LOOP:
+						FunctionCode parentFunc = FunctionIdentifier.getParentFunc(func.FunctionCode);
+						//if (parentFunc == FunctionCode.__NULL__)
+						//    throw new ExeEE("何か変?");
+						if ((nestStack.Count == 0)
+							|| (nestStack.Peek().FunctionCode != parentFunc))
+						{
+							ParserMediator.Warn("対応する" + parentFunc + "の無い" + func.Function.Name + "文です", func, 2, true, false);
+							break;
+						}
+						pairLine = nestStack.Pop();//REPEAT
+						func.JumpTo = pairLine;
+						pairLine.JumpTo = func;
+						break;
+					case FunctionCode.CATCH:
+						pairLine = nestStack.Count == 0 ? null : nestStack.Peek();
+						if ((pairLine == null)
+							|| ((pairLine.FunctionCode != FunctionCode.TRYCGOTO)
+							&& (pairLine.FunctionCode != FunctionCode.TRYCCALL)
+							&& (pairLine.FunctionCode != FunctionCode.TRYCJUMP)
+							&& (pairLine.FunctionCode != FunctionCode.TRYCGOTOFORM)
+							&& (pairLine.FunctionCode != FunctionCode.TRYCCALLFORM)
+							&& (pairLine.FunctionCode != FunctionCode.TRYCJUMPFORM)))
+						{
+							ParserMediator.Warn("対応するTRYC系命令がありません", func, 2, true, false);
+							break;
+						}
+						pairLine = nestStack.Pop();//TRYC
+						pairLine.JumpToEndCatch = func;//TRYCにCATCHの位置を教える
+						nestStack.Push(func);
+						break;
+					case FunctionCode.ENDCATCH:
+						if ((nestStack.Count == 0)
+							|| (nestStack.Peek().FunctionCode != FunctionCode.CATCH))
+						{
+							ParserMediator.Warn("対応するCATCHのないENDCATCHです", func, 2, true, false);
+							break;
+						}
+						pairLine = nestStack.Pop();//CATCH
+						pairLine.JumpToEndCatch = func;//CATCHにENDCATCHの位置を教える
+						break;
+                    case FunctionCode.PRINTDATA:
+                    case FunctionCode.PRINTDATAL:
+                    case FunctionCode.PRINTDATAW:
+                    case FunctionCode.PRINTDATAD:
+                    case FunctionCode.PRINTDATADL:
+                    case FunctionCode.PRINTDATADW:
+                    case FunctionCode.PRINTDATAK:
+                    case FunctionCode.PRINTDATAKL:
+                    case FunctionCode.PRINTDATAKW:
+                        {
+                            foreach (InstructionLine iLine in nestStack)
+                            {
+                                if (iLine.Function.IsPrintData())
+                                {
+                                    ParserMediator.Warn("PRINTDATA系命令が入れ子にされています", func, 2, true, false);
+                                    break;
+                                }
+                                if (iLine.FunctionCode == FunctionCode.STRDATA)
+                                {
+                                    ParserMediator.Warn("PRINTDATA系命令の中にSTRDATA系命令が含まれています", func, 2, true, false);
+                                    break;
+                                }
+                            }
+                            if (func.IsError)
+                                break;
+                            func.dataList = new List<List<InstructionLine>>();
+                            nestStack.Push(func);
+                            break;
+                        }
+                    case FunctionCode.STRDATA:
+                        {
+                            foreach (InstructionLine iLine in nestStack)
+                            {
+                                if (iLine.FunctionCode == FunctionCode.STRDATA)
+                                {
+                                    ParserMediator.Warn("STRDATA命令が入れ子にされています", func, 2, true, false);
+                                    break;
+                                }
+                                if (iLine.Function.IsPrintData())
+                                {
+                                    ParserMediator.Warn("STRDATA系命令の中にPRINTDATA系命令が含まれています", func, 2, true, false);
+                                    break;
+                                }
+                            }
+                            if (func.IsError)
+                                break;
+                            func.dataList = new List<List<InstructionLine>>();
+                            nestStack.Push(func);
+                            break;
+                        }
+                    case FunctionCode.DATALIST:
+                        {
+                            InstructionLine pline = (nestStack.Count == 0) ? null : nestStack.Peek();
+                            if ((pline == null) || ((!pline.Function.IsPrintData()) && (pline.FunctionCode != FunctionCode.STRDATA)))
+                            {
+                                ParserMediator.Warn("対応するPRINTDATA系命令のないDATALISTです", func, 2, true, false);
+                                break;
+                            }
+                            tempLineList = new List<InstructionLine>();
+                            nestStack.Push(func);
+
+                            break;
+                        }
+                    case FunctionCode.ENDLIST:
+                        {
+                            if ((nestStack.Count == 0) || (nestStack.Peek().FunctionCode != FunctionCode.DATALIST))
+                            {
+                                ParserMediator.Warn("対応するDATALISTのないENDLISTです", func, 2, true, false);
+                                break;
+                            }
+                            if (tempLineList.Count == 0)
+                                ParserMediator.Warn("DATALIST命令に表示データが与えられていません(このDATALISTは空文字列を表示します)", func, 1, false, false);
+                            nestStack.Pop();
+                            nestStack.Peek().dataList.Add(tempLineList);
+                            break;
+                        }
+                    case FunctionCode.DATA:
+                    case FunctionCode.DATAFORM:
+                        {
+                            InstructionLine pdata = (nestStack.Count == 0) ? null : nestStack.Peek();
+                            if ((pdata == null) || (!pdata.Function.IsPrintData() && pdata.FunctionCode != FunctionCode.DATALIST && pdata.FunctionCode != FunctionCode.STRDATA))
+                            {
+                                ParserMediator.Warn("対応するPRINTDATA系命令のない" + func.Function.Name + "です", func, 2, true, false);
+                                break;
+                            }
+                            List<InstructionLine> iList = new List<InstructionLine>();
+                            if (pdata.FunctionCode != FunctionCode.DATALIST)
+                            {
+                                iList.Add(func);
+                                pdata.dataList.Add(iList);
+                            }
+                            else
+                                tempLineList.Add(func);
+                            break;
+                        }
+                    case FunctionCode.ENDDATA:
+                        {
+                            InstructionLine pline = (nestStack.Count == 0) ? null : nestStack.Peek();
+                            if ((pline == null) || ((!pline.Function.IsPrintData()) && (pline.FunctionCode != FunctionCode.STRDATA)))
+                            {
+                                ParserMediator.Warn("対応するPRINTDATA系命令もしくはSTRDATAのない" + func.Function.Name + "です", func, 2, true, false);
+                                break;
+                            }
+                            if (pline.FunctionCode == FunctionCode.DATALIST)
+                                ParserMediator.Warn("DATALISTが閉じられていません", func, 2, true, false);
+                            if (pline.dataList.Count == 0)
+                                ParserMediator.Warn(pline.Function.Name + "命令に表示データがありません(この命令は無視されます)", func, 1, false, false);
+                            pline.JumpTo = func;
+                            nestStack.Pop();
+                            break;
+                        }
+					case FunctionCode.TRYCALLLIST:
+					case FunctionCode.TRYJUMPLIST:
+					case FunctionCode.TRYGOTOLIST:
+						foreach (InstructionLine iLine in nestStack)
+						{
+							if (iLine.FunctionCode == FunctionCode.TRYCALLLIST || iLine.FunctionCode == FunctionCode.TRYJUMPLIST || iLine.FunctionCode == FunctionCode.TRYGOTOLIST)
+							{
+								ParserMediator.Warn("TRYCALLLIST系命令が入れ子にされています", func, 2, true, false);
+								break;
+							}
+						}
+						if (func.IsError)
+							break;
+						func.callList = new List<InstructionLine>();
+						nestStack.Push(func);
+						break;
+					case FunctionCode.FUNC:
+						{
+							InstructionLine pFunc = (nestStack.Count == 0) ? null : nestStack.Peek();
+							if ((pFunc == null) ||
+								(pFunc.FunctionCode != FunctionCode.TRYCALLLIST && pFunc.FunctionCode != FunctionCode.TRYJUMPLIST && pFunc.FunctionCode != FunctionCode.TRYGOTOLIST))
+							{
+								ParserMediator.Warn("対応するTRYCALLLIST系命令のない" + func.Function.Name + "です", func, 2, true, false);
+								break;
+							}
+                            if (func.Argument == null)
+                            {
+                                ParserMediator.Warn("TRYCALLLIST系命令中に無効な" + func.Function.Name + "が存在します", pFunc, 2, true, false);
+                                break;
+                            }
+							if (pFunc.FunctionCode == FunctionCode.TRYGOTOLIST)
+							{
+								if (((SpCallArgment)func.Argument).SubNames.Length != 0)
+								{
+									ParserMediator.Warn("TRYGOTOLISTの呼び出し対象に[~~]が設定されています", func, 2, true, false);
+									break;
+								}
+								if (((SpCallArgment)func.Argument).RowArgs.Length != 0)
+								{
+									ParserMediator.Warn("TRYGOTOLISTの呼び出し対象に引数が設定されています", func, 2, true, false);
+									break;
+								}
+							}
+							pFunc.callList.Add(func);
+							break;
+						}
+					case FunctionCode.ENDFUNC:
+						InstructionLine pf = (nestStack.Count == 0) ? null : nestStack.Peek();
+						if ((pf == null) ||
+							(pf.FunctionCode != FunctionCode.TRYCALLLIST && pf.FunctionCode != FunctionCode.TRYJUMPLIST && pf.FunctionCode != FunctionCode.TRYGOTOLIST))
+						{
+							ParserMediator.Warn("対応するTRYCALLLIST系命令のない" + func.Function.Name + "です", func, 2, true, false);
+							break;
+						}
+						pf.JumpTo = func;
+						nestStack.Pop();
+						break;
+					case FunctionCode.NOSKIP:
+						foreach (InstructionLine iLine in nestStack)
+						{
+							if (iLine.FunctionCode == FunctionCode.NOSKIP)
+							{
+								ParserMediator.Warn("NOSKIP系命令が入れ子にされています", func, 2, true, false);
+								break;
+							}
+						}
+						if (func.IsError)
+							break;
+						nestStack.Push(func);
+						break;
+					case FunctionCode.ENDNOSKIP:
+						InstructionLine pfunc = (nestStack.Count == 0) ? null : nestStack.Peek();
+						if ((pfunc == null) ||
+							(pfunc.FunctionCode != FunctionCode.NOSKIP))
+						{
+							ParserMediator.Warn("対応するNOSKIP系命令のない" + func.Function.Name + "です", func, 2, true, false);
+							break;
+						}
+						//エラーハンドリング用
+						pfunc.JumpTo = func;
+						func.JumpTo = pfunc;
+						nestStack.Pop();
+						break;
+				}
+
+			}
+
+			while (nestStack.Count != 0)
+			{
+				InstructionLine func = nestStack.Pop();
+				string funcName = func.Function.Name;
+				string funcMatch = FunctionIdentifier.getMatchFunction(func.FunctionCode);
+				if (func != null)
+					ParserMediator.Warn(funcName + " is missing corresponding " + funcMatch, func, 2, true, false);
+				else
+					ParserMediator.Warn("ディフォルトエラー(Emuera設定漏れ)", func, 2, true, false);
+			}
+            //使ったスタックをクリア
+            SelectcaseStack.Clear();
+		}
+
+		private void setJumpTo(FunctionLabelLine label)
+		{
+			//3周目/3周
+			//フロー制御命令のジャンプ先を設定
+			LogicalLine nextLine = label;
+			int depth = label.Depth;
+			if (depth < 0)
+				depth = -2;
+			while (true)
+			{
+				nextLine = nextLine.NextLine;
+				InstructionLine func = nextLine as InstructionLine;
+				if (func == null)
+				{
+					if ((nextLine is NullLine) || (nextLine is FunctionLabelLine))
+						break;
+					continue;
+				}
+				if (func.IsError)
+					continue;
+				parentProcess.scaningLine = func;
+
+				if (func.Function.Instruction != null)
+				{
+					string FunctionNotFoundName = null;
+					try
+					{
+						func.Function.Instruction.SetJumpTo(ref useCallForm, func, depth, ref FunctionNotFoundName);
+					}
+					catch (CodeEE e)
+					{
+						ParserMediator.Warn(e.Message, func, 2, true, false);
+						continue;
+					}
+					if (FunctionNotFoundName != null)
+					{
+						if (!Program.AnalysisMode)
+							printFunctionNotFoundWarning("指定された関数名\"@" + FunctionNotFoundName + "\"は存在しません", func, 2, true);
+						else
+							printFunctionNotFoundWarning(FunctionNotFoundName, func, 2, true);
+					}
+                    continue;
+				}
+				if ((func.FunctionCode == FunctionCode.TRYCALLLIST) || (func.FunctionCode == FunctionCode.TRYJUMPLIST))
+					useCallForm = true;
+			}
+		}
+
+	}
+}

+ 526 - 0
NTERA/Game/GameProc/Function/Argument.cs

@@ -0,0 +1,526 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.GameData.Function;
+using MinorShift.Emuera.GameData.Variable;
+
+namespace MinorShift.Emuera.GameProc.Function
+{
+	internal abstract class Argument
+	{
+		public bool IsConst;
+		public string ConstStr;
+		public Int64 ConstInt;
+	}
+
+	internal sealed class VoidArgument : Argument
+	{
+	}
+
+	internal sealed class ErrorArgument : Argument
+	{
+		public ErrorArgument(string errorMes)
+		{
+			this.errorMes = errorMes;
+		}
+		readonly string errorMes;
+	}
+
+	internal sealed class ExpressionArgument : Argument
+	{
+		public ExpressionArgument(IOperandTerm termSrc)
+		{
+			Term = termSrc;
+		}
+		public readonly IOperandTerm Term;
+	}
+
+	internal sealed class ExpressionArrayArgument : Argument
+	{
+		public ExpressionArrayArgument(List<IOperandTerm> termList)
+		{
+			TermList = new IOperandTerm[termList.Count];
+			termList.CopyTo(TermList);
+		}
+		public readonly IOperandTerm[] TermList;
+	}
+
+	internal sealed class SpPrintVArgument : Argument
+	{
+		public SpPrintVArgument(IOperandTerm[] list)
+		{
+			Terms = list;
+		}
+		public readonly IOperandTerm[] Terms;
+	}
+
+	internal sealed class SpTimesArgument : Argument
+	{
+		public SpTimesArgument(VariableTerm var, double d)
+		{
+			VariableDest = var;
+			DoubleValue = d;
+		}
+		public readonly VariableTerm VariableDest;
+		public readonly double DoubleValue;
+	}
+
+	internal sealed class SpBarArgument : Argument
+	{
+		public SpBarArgument(IOperandTerm value, IOperandTerm max, IOperandTerm length)
+		{
+			Terms[0] = value;
+			Terms[1] = max;
+			Terms[2] = length;
+		}
+		public readonly IOperandTerm[] Terms = new IOperandTerm[3];
+	}
+
+
+	internal sealed class SpSwapCharaArgument : Argument
+	{
+		public SpSwapCharaArgument(IOperandTerm x, IOperandTerm y)
+		{
+			X = x;
+			Y = y;
+		}
+		public readonly IOperandTerm X;
+		public readonly IOperandTerm Y;
+	}
+
+	internal sealed class SpSwapVarArgument : Argument
+	{
+		public SpSwapVarArgument(VariableTerm v1, VariableTerm v2)
+		{
+			var1 = v1;
+			var2 = v2;
+		}
+		public readonly VariableTerm var1;
+		public readonly VariableTerm var2;
+	}
+
+	internal sealed class SpVarsizeArgument : Argument
+	{
+		public SpVarsizeArgument(VariableToken var)
+		{
+			VariableID = var;
+		}
+		public readonly VariableToken VariableID;
+	}
+
+	internal sealed class SpSaveDataArgument : Argument
+	{
+		public SpSaveDataArgument(IOperandTerm target, IOperandTerm var)
+		{
+			Target = target;
+			StrExpression = var;
+		}
+		public readonly IOperandTerm Target;
+		public readonly IOperandTerm StrExpression;
+	}
+
+	internal sealed class SpTInputsArgument : Argument
+	{
+		public SpTInputsArgument(IOperandTerm time, IOperandTerm def, IOperandTerm disp, IOperandTerm timeout)
+		{
+			Time = time;
+			Def = def;
+			Disp = disp;
+            Timeout = timeout;
+		}
+		public readonly IOperandTerm Time;
+		public readonly IOperandTerm Def;
+		public readonly IOperandTerm Disp;
+        public readonly IOperandTerm Timeout;
+	}
+
+	//難読化用属性。enum.ToString()やenum.Parse()を行うなら(Exclude=true)にすること。
+	[Obfuscation(Exclude = false)]
+	internal enum SortOrder
+	{
+		UNDEF = 0,
+		ASCENDING = 1,
+		DESENDING = 2
+	}
+
+	internal sealed class SpSortcharaArgument : Argument
+	{
+		public SpSortcharaArgument(VariableTerm var, SortOrder order)
+		{
+			SortKey = var;
+			SortOrder = order;
+		}
+		public readonly VariableTerm SortKey;
+		public readonly SortOrder SortOrder;
+	}
+
+	internal sealed class SpCallFArgment : Argument
+	{
+		public SpCallFArgment(IOperandTerm funcname, IOperandTerm[] subNames, IOperandTerm[] args)
+		{
+			FuncnameTerm = funcname;
+			SubNames = subNames;
+			RowArgs = args;
+		}
+		public readonly IOperandTerm FuncnameTerm;
+		public readonly IOperandTerm[] SubNames;
+		public readonly IOperandTerm[] RowArgs;
+		public IOperandTerm FuncTerm;
+	}
+
+	internal sealed class SpCallArgment : Argument
+	{
+		public SpCallArgment(IOperandTerm funcname, IOperandTerm[] subNames, IOperandTerm[] args)
+		{
+			FuncnameTerm = funcname;
+			SubNames = subNames;
+			RowArgs = args;
+		}
+		public readonly IOperandTerm FuncnameTerm;
+		public readonly IOperandTerm[] SubNames;
+		public readonly IOperandTerm[] RowArgs;
+		public UserDefinedFunctionArgument UDFArgument;
+		public CalledFunction CallFunc;
+	}
+
+	internal sealed class SpForNextArgment : Argument
+	{
+		public SpForNextArgment(VariableTerm var, IOperandTerm start, IOperandTerm end, IOperandTerm step)
+		{
+			Cnt = var;
+			Start = start;
+			End = end;
+			Step = step;
+		}
+		public readonly VariableTerm Cnt;
+		public readonly IOperandTerm Start;
+		public readonly IOperandTerm End;
+		public readonly IOperandTerm Step;
+	}
+
+	internal sealed class SpPowerArgument : Argument
+	{
+		public SpPowerArgument(VariableTerm var, IOperandTerm x, IOperandTerm y)
+		{
+			VariableDest = var;
+			X = x;
+			Y = y;
+		}
+		public readonly VariableTerm VariableDest;
+		public readonly IOperandTerm X;
+		public readonly IOperandTerm Y;
+	}
+
+	internal sealed class CaseArgument : Argument
+	{
+		public CaseArgument(CaseExpression[] args)
+		{
+			CaseExps = args;
+		}
+		public readonly CaseExpression[] CaseExps;
+	}
+
+	internal sealed class PrintDataArgument : Argument
+	{
+		public PrintDataArgument(VariableTerm var)
+		{
+			Var = var;
+		}
+		public readonly VariableTerm Var;
+	}
+
+    internal sealed class StrDataArgument : Argument
+    {
+        public StrDataArgument(VariableTerm var)
+        {
+            Var = var;
+        }
+        public readonly VariableTerm Var;
+    }
+
+	internal sealed class MethodArgument : Argument
+	{
+		public MethodArgument(IOperandTerm method)
+		{
+			MethodTerm = method;
+		}
+		public readonly IOperandTerm MethodTerm;
+	}
+
+	internal sealed class BitArgument : Argument
+	{
+		public BitArgument(VariableTerm var, IOperandTerm[] termSrc)
+		{
+			VariableDest = var;
+			Term = termSrc;
+		}
+		public readonly VariableTerm VariableDest;
+		public readonly IOperandTerm[] Term;
+	}
+
+	internal sealed class SpVarSetArgument : Argument
+	{
+		public SpVarSetArgument(VariableTerm var, IOperandTerm termSrc, IOperandTerm start, IOperandTerm end)
+		{
+			VariableDest = var;
+			Term = termSrc;
+			Start = start;
+			End = end;
+		}
+		public readonly VariableTerm VariableDest;
+		public readonly IOperandTerm Term;
+		public readonly IOperandTerm Start;
+		public readonly IOperandTerm End;
+	}
+
+	internal sealed class SpCVarSetArgument : Argument
+	{
+		public SpCVarSetArgument(VariableTerm var, IOperandTerm indexTerm, IOperandTerm termSrc, IOperandTerm start, IOperandTerm end)
+		{
+			VariableDest = var;
+			Index = indexTerm;
+			Term = termSrc;
+			Start = start;
+			End = end;
+		}
+		public readonly VariableTerm VariableDest;
+		public readonly IOperandTerm Index;
+		public readonly IOperandTerm Term;
+		public readonly IOperandTerm Start;
+		public readonly IOperandTerm End;
+	}
+
+	internal sealed class SpButtonArgument : Argument
+	{
+		public SpButtonArgument(IOperandTerm p1, IOperandTerm p2)
+		{
+			PrintStrTerm = p1;
+			ButtonWord = p2;
+		}
+		public readonly IOperandTerm PrintStrTerm;
+		public readonly IOperandTerm ButtonWord;
+	}
+
+
+	internal sealed class SpColorArgument : Argument
+	{
+		public SpColorArgument(IOperandTerm r, IOperandTerm g, IOperandTerm b)
+		{
+			R = r;
+			G = g;
+			B = b;
+		}
+		public SpColorArgument(IOperandTerm rgb)
+		{
+			RGB = rgb;
+		}
+		public readonly IOperandTerm R;
+		public readonly IOperandTerm G;
+		public readonly IOperandTerm B;
+		public readonly IOperandTerm RGB;
+	}
+
+	internal sealed class SpSplitArgument : Argument
+	{
+		public SpSplitArgument(IOperandTerm s1, IOperandTerm s2, VariableToken varId, VariableTerm num)
+		{
+			TargetStr = s1;
+			Split = s2;
+			Var = varId;
+            Num = num;
+		}
+		public readonly IOperandTerm TargetStr;
+		public readonly IOperandTerm Split;
+		public readonly VariableToken Var;
+        public readonly VariableTerm Num;
+	}
+	
+	internal sealed class SpHtmlSplitArgument : Argument
+	{
+		public SpHtmlSplitArgument(IOperandTerm s1,VariableToken varId, VariableTerm num)
+		{
+			TargetStr = s1;
+			Var = varId;
+            Num = num;
+		}
+		public readonly IOperandTerm TargetStr;
+		public readonly VariableToken Var;
+        public readonly VariableTerm Num;
+	}
+
+	internal sealed class SpGetIntArgument : Argument
+	{
+		public SpGetIntArgument(VariableTerm var)
+		{
+			VarToken = var;
+		}
+		public readonly VariableTerm VarToken;
+	}
+
+	internal sealed class SpArrayControlArgument : Argument
+	{
+		public SpArrayControlArgument(VariableTerm var, IOperandTerm num1, IOperandTerm num2)
+		{
+			VarToken = var;
+			Num1 = num1;
+			Num2 = num2;
+		}
+		public readonly VariableTerm VarToken;
+		public readonly IOperandTerm Num1;
+		public readonly IOperandTerm Num2;
+	}
+
+	internal sealed class SpArrayShiftArgument : Argument
+	{
+		public SpArrayShiftArgument(VariableTerm var, IOperandTerm num1, IOperandTerm num2, IOperandTerm num3, IOperandTerm num4)
+		{
+			VarToken = var;
+			Num1 = num1;
+			Num2 = num2;
+			Num3 = num3;
+			Num4 = num4;
+		}
+		public readonly VariableTerm VarToken;
+		public readonly IOperandTerm Num1;
+		public readonly IOperandTerm Num2;
+		public readonly IOperandTerm Num3;
+		public readonly IOperandTerm Num4;
+	}
+
+    internal sealed class SpArraySortArgument : Argument
+    {
+        public SpArraySortArgument(VariableTerm var, SortOrder order, IOperandTerm num1, IOperandTerm num2)
+        {
+            VarToken = var;
+            Order = order;
+            Num1 = num1;
+            Num2 = num2;
+        }
+        public readonly VariableTerm VarToken;
+        public readonly SortOrder Order;
+        public readonly IOperandTerm Num1;
+        public readonly IOperandTerm Num2;
+    }
+
+    internal sealed class SpCopyArrayArgument : Argument
+    {
+        public SpCopyArrayArgument(IOperandTerm str1, IOperandTerm str2)
+        {
+            VarName1 = str1;
+            VarName2 = str2;
+        }
+        public readonly IOperandTerm VarName1;
+        public readonly IOperandTerm VarName2;
+    }
+
+	internal sealed class SpSaveVarArgument : Argument
+	{
+		public SpSaveVarArgument(IOperandTerm term, IOperandTerm mes, VariableToken[] varTokens)
+		{
+			Term = term;
+			SavMes = mes;
+			VarTokens = varTokens;
+		}
+		public readonly IOperandTerm Term;
+		public readonly IOperandTerm SavMes;
+		public readonly VariableToken[] VarTokens;
+	}
+
+	internal sealed class RefArgument : Argument
+	{
+		public RefArgument(UserDefinedRefMethod udrm, UserDefinedRefMethod src)
+		{
+			RefMethodToken = udrm;
+			SrcRefMethodToken = src;
+		}
+		public RefArgument(UserDefinedRefMethod udrm, CalledFunction src)
+		{
+			RefMethodToken = udrm;
+			SrcCalledFunction = src;
+		}
+		public RefArgument(UserDefinedRefMethod udrm, IOperandTerm src)
+		{
+			RefMethodToken = udrm;
+			SrcTerm = src;
+		}
+		
+		public RefArgument(ReferenceToken vt, VariableToken src)
+		{
+			RefVarToken = vt;
+			SrcVarToken = src;
+		}
+		public RefArgument(ReferenceToken vt, IOperandTerm src)
+		{
+			RefVarToken = vt;
+			SrcTerm = src;
+		}
+		public readonly UserDefinedRefMethod RefMethodToken;
+		public readonly UserDefinedRefMethod SrcRefMethodToken;
+		public readonly CalledFunction SrcCalledFunction;
+
+		public readonly ReferenceToken RefVarToken;
+		public readonly VariableToken SrcVarToken;
+		public readonly IOperandTerm SrcTerm;
+	}
+
+    internal sealed class OneInputArgument : Argument
+    {
+        public OneInputArgument(IOperandTerm term, IOperandTerm flag)
+        {
+            Term = term;
+            Flag = flag;
+        }
+        public readonly IOperandTerm Term;
+        public readonly IOperandTerm Flag;
+    }
+
+    internal sealed class OneInputsArgument : Argument
+    {
+        public OneInputsArgument(IOperandTerm term, IOperandTerm flag)
+        {
+            Term = term;
+            Flag = flag;
+        }
+        public readonly IOperandTerm Term;
+        public readonly IOperandTerm Flag;
+    }
+    
+	#region set系
+	internal sealed class SpSetArgument : Argument
+	{
+		public SpSetArgument(VariableTerm var, IOperandTerm termSrc)
+		{
+			VariableDest = var;
+			Term = termSrc;
+		}
+		public readonly VariableTerm VariableDest;
+		public readonly IOperandTerm Term;
+		public bool AddConst = false;
+	}
+
+	internal sealed class SpSetArrayArgument : Argument
+	{
+		public SpSetArrayArgument(VariableTerm var, IOperandTerm[] termList, Int64[] constList)
+		{
+			VariableDest = var;
+			TermList = termList;
+			ConstIntList = constList;
+		}
+		public SpSetArrayArgument(VariableTerm var, IOperandTerm[] termList, string[] constList)
+		{
+			VariableDest = var;
+			TermList = termList;
+			ConstStrList = constList;
+		}
+		public readonly VariableTerm VariableDest;
+		public readonly IOperandTerm[] TermList;
+		public readonly Int64[] ConstIntList;
+		public readonly string[] ConstStrList;
+	}
+	#endregion
+
+
+
+
+}

+ 1888 - 0
NTERA/Game/GameProc/Function/ArgumentBuilder.cs

@@ -0,0 +1,1888 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using Microsoft.VisualBasic;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.GameData.Function;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameProc.Function
+{
+	internal abstract class ArgumentBuilder
+	{
+		protected void assignwarn(string mes, InstructionLine line, int level, bool isBackComp)
+		{
+			bool isError = level >= 2;
+			if (isError)
+			{
+				line.IsError = true;
+				line.ErrMes = mes;
+			}
+			ParserMediator.Warn(mes, line, level, isError, isBackComp);
+		}
+		protected void warn(string mes, InstructionLine line, int level, bool isBackComp)
+		{
+			mes = line.Function.Name + " Instruction:" + mes;
+			bool isError = level >= 2;
+			if (isError)
+			{
+				line.IsError = true;
+				line.ErrMes = mes;
+			}
+			ParserMediator.Warn(mes, line, level, isError, isBackComp);
+		}
+		/// <summary>
+		/// 引数の型と数。typeof(void)で任意の型(あるいは個別にチェックするべき引数)。nullでその引数は省略可能
+		/// </summary>
+		protected Type[] argumentTypeArray;//
+		/// <summary>
+		/// 最低限必要な引数の数。設定しないと全て省略不可。
+		/// </summary>
+		protected int minArg = -1;
+		/// <summary>
+		/// 引数の数に制限なし。
+		/// </summary>
+		protected bool argAny;
+		protected bool checkArgumentType(InstructionLine line, ExpressionMediator exm, IOperandTerm[] arguments)
+		{
+			if (arguments == null)
+			{
+				warn("Missing argument", line, 2, false);
+				return false;
+			}
+			if ( arguments.Length < minArg || 
+				((arguments.Length < argumentTypeArray.Length) && (minArg < 0)) )
+			{
+				warn("Not enough arguments", line, 2, false);
+				return false;
+			}
+			int length = arguments.Length;
+			if ((arguments.Length > argumentTypeArray.Length)&&(!argAny))
+			{
+				warn("Too many arguments", line, 1, false);
+				length = argumentTypeArray.Length;
+			}
+			for (int i = 0; i < length; i++)
+			{
+				Type allowType;
+				if ((!argAny) && (argumentTypeArray[i] == null))
+					continue;
+				if (argAny && i >= argumentTypeArray.Length)
+					allowType = argumentTypeArray[argumentTypeArray.Length - 1];
+				else
+					allowType = argumentTypeArray[i];
+				if (arguments[i] == null)
+				{
+					if (allowType == null)
+						continue;
+					warn("Argument number " + (i + 1) + ": unable to recognize argument", line, 2, false);
+					return false;
+				}
+				if ((allowType != typeof(void)) && (allowType != arguments[i].GetOperandType()))
+				{
+					warn("Argument number " + (i + 1) + ": argument type is incorrect", line, 2, false);
+					return false;
+				}
+			}
+			length = arguments.Length;
+			for (int i = 0; i < length; i++)
+			{
+				if (arguments[i] == null)
+					continue;
+				arguments[i] = arguments[i].Restructure(exm);
+			}
+			return true;
+		}
+
+		protected VariableTerm getChangeableVariable(IOperandTerm[] terms, int i, InstructionLine line)
+		{
+			VariableTerm varTerm = terms[i - 1] as VariableTerm;
+			if (varTerm == null)
+			{
+				warn("第" + i + "引数に変数以外を指定することはできません", line, 2, false);
+				return null;
+			}
+
+			if (varTerm.Identifier.IsConst)
+			{
+				warn("第" + i + "引数に変更できない変数を指定することはできません", line, 2, false);
+				return null;
+			}
+			return varTerm;
+		}
+
+		protected WordCollection popWords(InstructionLine line)
+		{
+			StringStream st = line.PopArgumentPrimitive();
+			return LexicalAnalyzer.Analyse(st, LexEndWith.EoL, LexAnalyzeFlag.None);
+		}
+
+		protected IOperandTerm[] popTerms(InstructionLine line)
+		{
+			StringStream st = line.PopArgumentPrimitive();
+			WordCollection wc = LexicalAnalyzer.Analyse(st, LexEndWith.EoL, LexAnalyzeFlag.None);
+			return ExpressionParser.ReduceArguments(wc, ArgsEndWith.EoL, false);
+		}
+		public abstract Argument CreateArgument(InstructionLine line, ExpressionMediator exm);
+	}
+
+
+	internal static partial class ArgumentParser
+	{
+		static readonly Dictionary<FunctionArgType, ArgumentBuilder> argb = new Dictionary<FunctionArgType, ArgumentBuilder>();
+		
+		public static Dictionary<FunctionArgType, ArgumentBuilder> GetArgumentBuilderDictionary()
+		{
+			return argb;
+		}
+		public static ArgumentBuilder GetArgumentBuilder(FunctionArgType key)
+		{
+			return argb[key];
+		}
+		
+		static ArgumentParser()
+		{
+			argb[FunctionArgType.METHOD] = new METHOD_ArgumentBuilder();
+			argb[FunctionArgType.VOID] = new VOID_ArgumentBuilder();
+			argb[FunctionArgType.INT_EXPRESSION] = new INT_EXPRESSION_ArgumentBuilder(false);
+			argb[FunctionArgType.INT_EXPRESSION_NULLABLE] = new INT_EXPRESSION_ArgumentBuilder(true);
+			argb[FunctionArgType.STR_EXPRESSION] = new STR_EXPRESSION_ArgumentBuilder(false);
+            argb[FunctionArgType.STR_EXPRESSION_NULLABLE] = new STR_EXPRESSION_ArgumentBuilder(true);
+            argb[FunctionArgType.STR] = new STR_ArgumentBuilder(false);
+			argb[FunctionArgType.STR_NULLABLE] = new STR_ArgumentBuilder(true);
+			argb[FunctionArgType.FORM_STR] = new FORM_STR_ArgumentBuilder(false);
+			argb[FunctionArgType.FORM_STR_NULLABLE] = new FORM_STR_ArgumentBuilder(true);
+			argb[FunctionArgType.SP_PRINTV] = new SP_PRINTV_ArgumentBuilder();
+			argb[FunctionArgType.SP_TIMES] = new SP_TIMES_ArgumentBuilder();
+			argb[FunctionArgType.SP_BAR] = new SP_BAR_ArgumentBuilder();
+			argb[FunctionArgType.SP_SET] = new SP_SET_ArgumentBuilder();
+			argb[FunctionArgType.SP_SETS] = new SP_SET_ArgumentBuilder();
+			argb[FunctionArgType.SP_SWAP] = new SP_SWAP_ArgumentBuilder(false);
+			argb[FunctionArgType.SP_VAR] = new SP_VAR_ArgumentBuilder();
+			argb[FunctionArgType.SP_SAVEDATA] = new SP_SAVEDATA_ArgumentBuilder();
+            argb[FunctionArgType.SP_TINPUT] = new SP_TINPUT_ArgumentBuilder();
+            argb[FunctionArgType.SP_TINPUTS] = new SP_TINPUTS_ArgumentBuilder();
+			argb[FunctionArgType.SP_SORTCHARA] = new SP_SORTCHARA_ArgumentBuilder();
+			argb[FunctionArgType.SP_CALL] = new SP_CALL_ArgumentBuilder(false, false);
+			argb[FunctionArgType.SP_CALLF] = new SP_CALL_ArgumentBuilder(true, false);
+			argb[FunctionArgType.SP_CALLFORM] = new SP_CALL_ArgumentBuilder(false, true);
+			argb[FunctionArgType.SP_CALLFORMF] = new SP_CALL_ArgumentBuilder(true, true);
+			argb[FunctionArgType.SP_FOR_NEXT] = new SP_FOR_NEXT_ArgumentBuilder();
+			argb[FunctionArgType.SP_POWER] = new SP_POWER_ArgumentBuilder();
+			argb[FunctionArgType.SP_SWAPVAR] = new SP_SWAPVAR_ArgumentBuilder();
+			argb[FunctionArgType.EXPRESSION] = new EXPRESSION_ArgumentBuilder(false);
+			argb[FunctionArgType.EXPRESSION_NULLABLE] = new EXPRESSION_ArgumentBuilder(true);
+			argb[FunctionArgType.CASE] = new CASE_ArgumentBuilder();
+			argb[FunctionArgType.VAR_INT] = new VAR_INT_ArgumentBuilder();
+            argb[FunctionArgType.VAR_STR] = new VAR_STR_ArgumentBuilder();
+			argb[FunctionArgType.BIT_ARG] = new BIT_ARG_ArgumentBuilder();
+			argb[FunctionArgType.SP_VAR_SET] = new SP_VAR_SET_ArgumentBuilder();
+			argb[FunctionArgType.SP_BUTTON] = new SP_BUTTON_ArgumentBuilder();
+			argb[FunctionArgType.SP_COLOR] = new SP_COLOR_ArgumentBuilder();
+			argb[FunctionArgType.SP_SPLIT] = new SP_SPLIT_ArgumentBuilder();
+			argb[FunctionArgType.SP_GETINT] = new SP_GETINT_ArgumentBuilder();
+			argb[FunctionArgType.SP_CVAR_SET] = new SP_CVAR_SET_ArgumentBuilder();
+			argb[FunctionArgType.SP_CONTROL_ARRAY] = new SP_CONTROL_ARRAY_ArgumentBuilder();
+			argb[FunctionArgType.SP_SHIFT_ARRAY] = new SP_SHIFT_ARRAY_ArgumentBuilder();
+            argb[FunctionArgType.SP_SORTARRAY] = new SP_SORT_ARRAY_ArgumentBuilder();
+			argb[FunctionArgType.INT_ANY] = new INT_ANY_ArgumentBuilder();
+			argb[FunctionArgType.FORM_STR_ANY] = new FORM_STR_ANY_ArgumentBuilder();
+            argb[FunctionArgType.SP_COPYCHARA] = new SP_SWAP_ArgumentBuilder(true);
+            argb[FunctionArgType.SP_INPUT] = new SP_INPUT_ArgumentBuilder();
+			argb[FunctionArgType.SP_INPUTS] = new SP_INPUTS_ArgumentBuilder();
+            argb[FunctionArgType.SP_COPY_ARRAY] = new SP_COPY_ARRAY_Arguments();
+			argb[FunctionArgType.SP_SAVEVAR] = new SP_SAVEVAR_ArgumentBuilder();
+			argb[FunctionArgType.SP_SAVECHARA] = new SP_SAVECHARA_ArgumentBuilder();
+			argb[FunctionArgType.SP_REF] = new SP_REF_ArgumentBuilder(false);
+			argb[FunctionArgType.SP_REFBYNAME] = new SP_REF_ArgumentBuilder(true);
+			argb[FunctionArgType.SP_HTMLSPLIT] = new SP_HTMLSPLIT_ArgumentBuilder();
+			
+        }
+		
+		private sealed class SP_PRINTV_ArgumentBuilder : ArgumentBuilder
+		{
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				StringStream st = line.PopArgumentPrimitive();
+				WordCollection wc = LexicalAnalyzer.Analyse(st, LexEndWith.EoL, LexAnalyzeFlag.AnalyzePrintV);
+				IOperandTerm[] args = ExpressionParser.ReduceArguments(wc, ArgsEndWith.EoL, false);
+				for(int i = 0; i< args.Length;i++)
+				{
+					if(args[i] == null)
+						{warn("Argument cannot be omitted", line, 2, false); return null;}
+
+					args[i] = args[i].Restructure(exm);
+				}
+				return new SpPrintVArgument(args);
+			}
+		}
+
+        private sealed class SP_TIMES_ArgumentBuilder : ArgumentBuilder
+		{
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				StringStream st = line.PopArgumentPrimitive();
+				WordCollection wc = LexicalAnalyzer.Analyse(st, LexEndWith.Comma, LexAnalyzeFlag.None);
+				st.ShiftNext();
+				if (st.EOS)
+					{warn("Not enough arguments", line, 2, false); return null;}
+				double d = 0.0;
+				try
+				{
+					LexicalAnalyzer.SkipWhiteSpace(st);
+					d = LexicalAnalyzer.ReadDouble(st);
+					LexicalAnalyzer.SkipWhiteSpace(st);
+					if (!st.EOS)
+						warn("Too many arguments", line, 1, false);
+				}
+				catch
+				{
+					warn("The second argument is not a real number (it is always interpreted as 0)", line, 1, false);
+					d = 0.0;
+				}
+				IOperandTerm term = ExpressionParser.ReduceExpressionTerm(wc, TermEndWith.EoL);
+				if (term == null)
+				{ warn("The format is wrong", line, 2, false); return null; }
+				VariableTerm varTerm = term.Restructure(exm) as VariableTerm;
+				if (varTerm == null)
+				{ warn("You cannot specify anything other than variables for the first argument", line, 2, false); return null; }
+
+				if (varTerm.IsString)
+				{ warn("The first argument cannot be a string variable", line, 2, false); return null; }
+
+				if (varTerm.Identifier.IsConst)
+				{ warn("It is not possible to specify a variable that cannot be changed as the first argument", line, 2, false); return null; }
+				return new SpTimesArgument(varTerm, d);
+			}
+		}
+		
+        private sealed class FORM_STR_ANY_ArgumentBuilder : ArgumentBuilder
+		{
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				Argument ret = null;
+				StringStream st = line.PopArgumentPrimitive();
+				List<IOperandTerm> termList = new List<IOperandTerm>();
+				LexicalAnalyzer.SkipHalfSpace(st);
+				if (st.EOS)
+				{
+					if (line.FunctionCode == FunctionCode.RETURNFORM)
+					{
+						termList.Add(new SingleTerm("0"));
+						ret = new ExpressionArrayArgument(termList);
+						ret.IsConst = true;
+						ret.ConstInt = 0;
+						return ret;
+					}
+					warn("Argument is not set", line, 2, false);
+					return null;
+				}
+				while (true)
+				{
+					StrFormWord sfwt = LexicalAnalyzer.AnalyseFormattedString(st, FormStrEndWith.Comma, false);
+					IOperandTerm term = ExpressionParser.ToStrFormTerm(sfwt);
+					term = term.Restructure(exm);
+					termList.Add(term);
+					st.ShiftNext();
+					if (st.EOS)
+						break;
+					LexicalAnalyzer.SkipHalfSpace(st);
+					if (st.EOS)
+					{
+					    warn("\',\' doesn't have an argument after it", line, 1, false);
+					    break;
+					}
+				}
+				return new ExpressionArrayArgument(termList);
+			}
+		}
+	
+		private sealed class VOID_ArgumentBuilder : ArgumentBuilder
+		{
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				StringStream st = line.PopArgumentPrimitive();
+				LexicalAnalyzer.SkipWhiteSpace(st);
+				if (!st.EOS)
+					warn("Argument is not required", line, 1, false);
+				return new VoidArgument();
+			}
+		}
+
+		private sealed class STR_ArgumentBuilder : ArgumentBuilder
+		{
+			public STR_ArgumentBuilder(bool nullable)
+			{
+				this.nullable = nullable;
+			}
+			bool nullable;
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				StringStream st = line.PopArgumentPrimitive();
+					string rowStr = null;
+				if (st.EOS)
+				{
+					if (!nullable)
+					{
+						warn("Argument is not set", line, 2, false);
+						return null;
+					}
+					rowStr = "";
+					//1756 処理変更のために完全に見分けが付かなくなってしまった
+					//if (line.FunctionCode == FunctionCode.PRINTL)
+					//	warn("PRINTLの後ろに空白がありません(eramaker:\'PRINTL\'を表示)", line, 0, true);
+				}
+				else
+					rowStr = st.Substring();
+                if (line.FunctionCode == FunctionCode.SETCOLORBYNAME || line.FunctionCode == FunctionCode.SETBGCOLORBYNAME)
+				{
+                    Color c = Color.FromName(rowStr);
+					if (c.A == 0)
+					{
+						if (rowStr.Equals("transparent", StringComparison.OrdinalIgnoreCase))
+							throw new CodeEE("無色透明(Transparent)は色として指定できません");
+						throw new CodeEE("指定された色名\"" + rowStr + "\"は無効な色名です");
+					}
+
+                }
+				Argument ret = new ExpressionArgument(new SingleTerm(rowStr));
+				ret.ConstStr = rowStr;
+				ret.IsConst = true;
+				return ret;
+			}
+		}
+
+		private sealed class FORM_STR_ArgumentBuilder : ArgumentBuilder
+		{
+			public FORM_STR_ArgumentBuilder(bool nullable)
+			{
+				this.nullable = nullable;
+			}
+			bool nullable;
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				StringStream st = line.PopArgumentPrimitive();
+				Argument ret = null;
+				if (st.EOS)
+				{
+					if(!nullable)
+					{
+						warn("Argument is not set", line, 2, false);
+						return null;
+					}
+					//if (line.FunctionCode == FunctionCode.PRINTFORML)
+					//	warn("PRINTFORMLの後ろに空白がありません(eramaker:\'PRINTFORML\'を表示)", line, 0, true);
+					ret = new ExpressionArgument(new SingleTerm(""));
+					
+					ret.ConstStr = "";
+					ret.IsConst = true;
+					return ret;
+				}
+				StrFormWord sfwt = LexicalAnalyzer.AnalyseFormattedString(st, FormStrEndWith.EoL, false);
+				IOperandTerm term = ExpressionParser.ToStrFormTerm(sfwt);
+				term = term.Restructure(exm);
+				ret = new ExpressionArgument(term);
+				if(term is SingleTerm)
+				{
+					ret.ConstStr = term.GetStrValue(exm);
+					ret.IsConst = true;
+				}
+				return ret;
+			}
+		}
+
+		private sealed class SP_VAR_ArgumentBuilder : ArgumentBuilder
+		{
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				StringStream st = line.PopArgumentPrimitive();
+                IdentifierWord iw = LexicalAnalyzer.ReadSingleIdentifierWord(st);
+                if (iw == null)
+                { warn("第1引数を読み取ることができません", line, 2, false); return null; }
+				string idStr = iw.Code;
+				VariableToken id = GlobalStatic.IdentifierDictionary.GetVariableToken(idStr, null, true);
+				if (id == null)
+				{ warn("You cannot specify anything other than variables for the first argument", line, 2, false); return null; }
+
+				if ((!id.IsArray1D && !id.IsArray2D && !id.IsArray3D) || (id.Code == VariableCode.RAND))
+				{ warn("第1引数に配列でない変数を指定することはできません", line, 2, false); return null; }
+				LexicalAnalyzer.SkipWhiteSpace(st);
+				if (!st.EOS)
+				{
+					warn("引数の後に余分な文字があります", line, 1, false);
+				}
+				return new SpVarsizeArgument(id);
+			}
+		}
+
+		private sealed class SP_SORTCHARA_ArgumentBuilder : ArgumentBuilder
+		{
+			
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				VariableTerm varTerm = new VariableTerm(GlobalStatic.VariableData.GetSystemVariableToken("NO"), new IOperandTerm[] { new SingleTerm(0) });
+				SortOrder order = SortOrder.ASCENDING;
+				WordCollection wc = popWords(line);
+				IdentifierWord id = wc.Current as IdentifierWord;
+				if (wc.EOL)
+				{
+					return new SpSortcharaArgument(varTerm, order);
+				}
+				if ((id != null) && (id.Code.Equals("FORWARD", Config.SCVariable)
+					|| (id.Code.Equals("BACK", Config.SCVariable))))
+				{
+					if (id.Code.Equals("BACK", Config.SCVariable))
+						order = SortOrder.DESENDING;
+					wc.ShiftNext();
+					if (!wc.EOL)
+						warn("Too many arguments", line, 1, false);
+				}
+				else
+				{
+					IOperandTerm term = ExpressionParser.ReduceExpressionTerm(wc, TermEndWith.Comma);
+					if (term == null)
+					{ warn("The format is wrong", line, 2, false); return null; }
+					varTerm = term.Restructure(exm) as VariableTerm;
+					if (varTerm == null)
+					{ warn("You cannot specify anything other than variables for the first argument", line, 2, false); return null; }
+
+					if (!varTerm.Identifier.IsCharacterData)
+					{ warn("The first argument must be a character variable", line, 2, false); return null; }
+					wc.ShiftNext();
+					if (!wc.EOL)
+					{
+						id = wc.Current as IdentifierWord;
+						if ((id != null) && (id.Code.Equals("FORWARD", Config.SCVariable)
+							|| (id.Code.Equals("BACK", Config.SCVariable))))
+						{
+							if (id.Code.Equals("BACK", Config.SCVariable))
+								order = SortOrder.DESENDING;
+							wc.ShiftNext();
+							if (!wc.EOL)
+								warn("Too many arguments", line, 1, false);
+						}
+						else
+						{ warn("The format is wrong", line, 2, false); return null; }
+					}
+				}
+				return new SpSortcharaArgument(varTerm, order);
+			}
+		}
+
+        private sealed class SP_SORT_ARRAY_ArgumentBuilder : ArgumentBuilder
+        {
+            public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+            {
+                SortOrder order = SortOrder.ASCENDING;
+                WordCollection wc = popWords(line);
+                IOperandTerm term3 = new SingleTerm(0);
+                IOperandTerm term4 = null;
+
+                if (wc.EOL)
+                {
+                    warn("The format is wrong", line, 2, false); return null;
+                }
+
+                VariableTerm varTerm;
+                IOperandTerm term = ExpressionParser.ReduceExpressionTerm(wc, TermEndWith.Comma);
+                if (term == null)
+                { warn("The format is wrong", line, 2, false); return null; }
+                varTerm = term.Restructure(exm) as VariableTerm;
+                if (varTerm == null)
+                { warn("You cannot specify anything other than variables for the first argument", line, 2, false); return null; }
+
+	            if (varTerm.Identifier.IsConst)
+	            { warn("The first argument cannot be changed", line, 2, false); return null; }
+	            if (!varTerm.Identifier.IsArray1D)
+                { warn("You cannot specify a non-one-dimensional array or array type character variable as the first argument", line, 2, false); return null; }
+
+                wc.ShiftNext();
+                IdentifierWord id = wc.Current as IdentifierWord;
+
+                if ((id != null) && (id.Code.Equals("FORWARD", Config.SCVariable) || (id.Code.Equals("BACK", Config.SCVariable))))
+                {
+                    if (id.Code.Equals("BACK", Config.SCVariable))
+                        order = SortOrder.DESENDING;
+                    wc.ShiftNext();
+                }
+                else if (id != null)
+                { warn("第2引数にソート方法指定子(FORWARD or BACK)以外が指定されています", line, 2, false); return null; }
+
+                if (id != null)
+                {
+                    wc.ShiftNext();
+                    if (!wc.EOL)
+                    {
+                        term3 = ExpressionParser.ReduceExpressionTerm(wc, TermEndWith.Comma);
+                        if (term3 == null)
+                        { warn("The third argument cannot be interpreted", line, 2, false); return null; }
+                        if (!term3.IsInteger)
+                        { warn("The third argument is not a number", line, 2, false); return null; }
+                        wc.ShiftNext();
+                        if (!wc.EOL)
+                        {
+                            term4 = ExpressionParser.ReduceExpressionTerm(wc, TermEndWith.Comma);
+                            if (term4 == null)
+                            { warn("The fourth argument cannot be interpreted", line, 2, false); return null; }
+                            if (!term4.IsInteger)
+                            { warn("The fourth argument is not a number", line, 2, false); return null; }
+                            wc.ShiftNext();
+                            if (!wc.EOL)
+                                warn("Too many arguments", line, 1, false);
+                        }
+                    }
+                }
+                return new SpArraySortArgument(varTerm, order, term3, term4);
+            }
+        }
+
+		private sealed class SP_CALL_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_CALL_ArgumentBuilder(bool callf, bool form)
+			{
+				this.form = form;
+				this.callf = callf;
+			}
+			bool form;
+			bool callf;
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				StringStream st = line.PopArgumentPrimitive();
+				IOperandTerm funcname = null;
+				if (form)
+				{
+					StrFormWord sfw = LexicalAnalyzer.AnalyseFormattedString(st, FormStrEndWith.LeftParenthesis_Bracket_Comma_Semicolon, true);
+					funcname = ExpressionParser.ToStrFormTerm(sfw);
+					funcname = funcname.Restructure(exm);
+				}
+				else
+				{
+					string str = LexicalAnalyzer.ReadString(st, StrEndWith.LeftParenthesis_Bracket_Comma_Semicolon);
+					str = str.Trim(' ', '\t');
+					funcname = new SingleTerm(str);
+				}
+				char cur = st.Current;
+				WordCollection wc = LexicalAnalyzer.Analyse(st, LexEndWith.EoL, LexAnalyzeFlag.None);
+				wc.ShiftNext();
+
+				IOperandTerm[] subNames = null;
+				IOperandTerm[] args = null;
+                if (cur == '[')
+                {
+                    subNames = ExpressionParser.ReduceArguments(wc, ArgsEndWith.RightBracket, false);
+                    if (!wc.EOL)
+                    {
+                        if (wc.Current.Type != '(')
+                        wc.ShiftNext();
+                        args = ExpressionParser.ReduceArguments(wc, ArgsEndWith.RightParenthesis, false);
+                    }
+                }
+				if ((cur == '(') || (cur == ','))
+				{
+					if (cur == '(')
+						args = ExpressionParser.ReduceArguments(wc, ArgsEndWith.RightParenthesis, false);
+					else
+						args = ExpressionParser.ReduceArguments(wc, ArgsEndWith.EoL, false);
+					if (!wc.EOL)
+					{ warn("The format is wrong", line, 2, false); return null; }
+				}
+				if (subNames == null)
+					subNames = new IOperandTerm[0];
+				if (args == null)
+					args = new IOperandTerm[0];
+				for(int i = 0; i < subNames.Length; i++)
+					if (subNames != null)
+						subNames[i] = subNames[i].Restructure(exm);
+				for(int i = 0; i < args.Length; i++)
+					if (args[i] != null)
+						args[i] = args[i].Restructure(exm);
+				Argument ret = null;
+				if(callf)
+					ret = new SpCallFArgment(funcname, subNames, args);
+				else
+					ret = new SpCallArgment(funcname, subNames, args);
+                if (funcname is SingleTerm)
+                {
+                    ret.IsConst = true;
+                    ret.ConstStr = funcname.GetStrValue(null);
+                    if (ret.ConstStr == "")
+                    {
+                        warn("Function name is not specified", line, 2, false);
+                        return null;
+                    }
+                }
+				return ret;
+			}
+		}
+
+		private sealed class CASE_ArgumentBuilder : ArgumentBuilder
+		{
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				WordCollection wc = popWords(line);
+				CaseExpression[] args = ExpressionParser.ReduceCaseExpressions(wc);
+				if ((!wc.EOL) || (args.Length == 0))
+				{ warn("The format is wrong", line, 2, false); return null; }
+				for(int i = 0; i < args.Length; i++)
+					args[i].Reduce(exm);
+				return new CaseArgument(args);
+			}
+		}
+		
+		private sealed class SP_SET_ArgumentBuilder : ArgumentBuilder
+		{
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm) 
+			{
+				WordCollection destWc = line.PopAssignmentDestStr();
+				IOperandTerm[] destTerms = ExpressionParser.ReduceArguments(destWc, ArgsEndWith.EoL, false);
+				SpSetArgument ret = null;
+				if ((destTerms.Length == 0) || (destTerms[0] == null))
+				{ assignwarn("Failed to read the left side of the assignment statement", line, 2, false); return null; }
+				if (destTerms.Length != 1)
+					{assignwarn("Left side of the assignment statement has an extra ','", line, 2, false); return null;}
+				VariableTerm varTerm = destTerms[0] as VariableTerm;
+				if (varTerm == null)
+				{//
+					assignwarn("You cannot specify anything other than variables on the left side of the assignment statement", line, 2, false);
+					return null;
+				}
+
+				if (varTerm.Identifier.IsConst)
+				{
+					assignwarn("It is not possible to specify a variable that cannot be changed on the left side of the assignment statement", line, 2, false);
+					return null;
+				}
+				varTerm.Restructure(exm);
+				StringStream st = line.PopArgumentPrimitive();
+                if (st == null)
+                    st = new StringStream("");
+                OperatorCode op = line.AssignOperator;
+				IOperandTerm src = null;
+				if(varTerm.IsInteger)
+				{
+					if (op == OperatorCode.AssignmentStr)
+						{ assignwarn("整数型の代入に演算子"+OperatorManager.ToOperatorString(op) + "は使用できません", line, 2, false); return null; }
+					if((op == OperatorCode.Increment)||(op == OperatorCode.Decrement))
+					{
+						LexicalAnalyzer.SkipWhiteSpace(st);
+						if (!st.EOS)
+						{
+							if (op == OperatorCode.Increment)
+								{assignwarn("インクリメント行でインクリメント以外の処理が定義されています", line, 2, false);return null;}
+
+							assignwarn("デクリメント行でデクリメント以外の処理が定義されています", line, 2, false);return null;
+						}
+						ret = new SpSetArgument(varTerm, null);
+						ret.IsConst = true;
+						if (op == OperatorCode.Increment)
+							ret.ConstInt = 1;
+						else
+							ret.ConstInt = -1;
+						ret.AddConst = true;
+						return ret;
+					}
+					WordCollection srcWc = LexicalAnalyzer.Analyse(st, LexEndWith.EoL, LexAnalyzeFlag.None);
+					IOperandTerm[] srcTerms = ExpressionParser.ReduceArguments(srcWc, ArgsEndWith.EoL, false);
+					
+					if ((srcTerms.Length == 0) || (srcTerms[0] == null))
+						{assignwarn("代入文の右辺の読み取りに失敗しました", line, 2, false); return null;}
+					if (srcTerms.Length != 1)
+					{
+						if(op != OperatorCode.Assignment)
+						{assignwarn("複合代入演算では右辺に複数の値を含めることはできません", line, 2, false); return null;}
+						bool allConst = true;
+						Int64[] constValues = new Int64[srcTerms.Length];
+						for (int i = 0; i < srcTerms.Length; i++)
+						{
+							if (srcTerms[i] == null)
+							{ assignwarn("代入式の右辺の値は省略できません", line, 2, false); return null; }
+							if (!srcTerms[i].IsInteger)
+							{ assignwarn("数値型変数に文字列は代入できません", line, 2, false); return null; }
+							srcTerms[i] = srcTerms[i].Restructure(exm);
+							if (allConst && (srcTerms[i] is SingleTerm))
+								constValues[i] = srcTerms[i].GetIntValue(null);
+							else
+								allConst = false;
+						}
+						SpSetArrayArgument arrayarg = new SpSetArrayArgument(varTerm, srcTerms, constValues);
+						arrayarg.IsConst = allConst;
+						return arrayarg;
+					}
+					if(!srcTerms[0].IsInteger)
+						{assignwarn("数値型変数に文字列は代入できません", line, 2, false); return null;}
+					src = srcTerms[0].Restructure(exm);
+					if(op == OperatorCode.Assignment)
+					{
+						ret = new SpSetArgument(varTerm, src);
+						if(src is SingleTerm)
+						{
+							ret.IsConst = true;
+							ret.AddConst = false;
+							ret.ConstInt = src.GetIntValue(null);
+						}
+						return ret;
+					}
+					if((op == OperatorCode.Plus)||(op == OperatorCode.Minus))
+					{
+						if(src is SingleTerm)
+						{
+							ret = new SpSetArgument(varTerm, null);
+							ret.IsConst = true;
+							ret.AddConst = true;
+							if (op == OperatorCode.Plus)
+								ret.ConstInt = src.GetIntValue(null);
+							else
+								ret.ConstInt = -src.GetIntValue(null);
+							return ret;
+						}
+					}
+					src = OperatorMethodManager.ReduceBinaryTerm(op,varTerm, src);
+					return new SpSetArgument(varTerm, src);
+					
+				}
+
+				if (op == OperatorCode.Assignment)
+				{
+					LexicalAnalyzer.SkipHalfSpace(st);//文字列の代入なら半角スペースだけを読み飛ばす
+					//eramakerは代入文では妙なTrim()をする。半端にしか再現できないがとりあえずtrim = true
+					StrFormWord sfwt = LexicalAnalyzer.AnalyseFormattedString(st, FormStrEndWith.EoL, true);
+					IOperandTerm term = ExpressionParser.ToStrFormTerm(sfwt);
+					src = term.Restructure(exm);
+					ret = new SpSetArgument(varTerm, src);
+					if (src is SingleTerm)
+					{
+						ret.IsConst = true;
+						ret.AddConst = false;
+						ret.ConstStr = src.GetStrValue(null);
+					}
+					return ret;
+				}
+
+				if ((op == OperatorCode.Mult)||(op == OperatorCode.Plus)||(op == OperatorCode.AssignmentStr))
+				{
+					WordCollection srcWc = LexicalAnalyzer.Analyse(st, LexEndWith.EoL, LexAnalyzeFlag.None);
+					IOperandTerm[] srcTerms = ExpressionParser.ReduceArguments(srcWc, ArgsEndWith.EoL, false);
+						
+					if ((srcTerms.Length == 0) || (srcTerms[0] == null))
+					{assignwarn("代入文の右辺の読み取りに失敗しました", line, 2, false); return null;}
+					if (op == OperatorCode.AssignmentStr)
+					{
+						if (srcTerms.Length == 1)
+						{
+							if (srcTerms[0].IsInteger)
+							{ assignwarn("文字列変数に数値型は代入できません", line, 2, false); return null; }
+							src = srcTerms[0].Restructure(exm);
+							ret = new SpSetArgument(varTerm, src);
+							if (src is SingleTerm)
+							{
+								ret.IsConst = true;
+								ret.AddConst = false;
+								ret.ConstStr = src.GetStrValue(null);
+							}
+							return ret;
+						}
+						bool allConst = true;
+						string[] constValues = new string[srcTerms.Length];
+						for (int i = 0; i < srcTerms.Length; i++)
+						{
+							if (srcTerms[i] == null)
+							{ assignwarn("代入式の右辺の値は省略できません", line, 2, false); return null; }
+							if (srcTerms[i].IsInteger)
+							{ assignwarn("文字列変数に数値型は代入できません", line, 2, false); return null; }
+							srcTerms[i] = srcTerms[i].Restructure(exm);
+							if (allConst && (srcTerms[i] is SingleTerm))
+								constValues[i] = srcTerms[i].GetStrValue(null);
+							else
+								allConst = false;
+						}
+						SpSetArrayArgument arrayarg = new SpSetArrayArgument(varTerm, srcTerms, constValues);
+						arrayarg.IsConst = allConst;
+						return arrayarg;
+					}
+					if (srcTerms.Length != 1)
+					{ assignwarn("代入文の右辺に余分な','があります", line, 2, false); return null; }
+							
+					src = srcTerms[0].Restructure(exm);
+					src = OperatorMethodManager.ReduceBinaryTerm(op, varTerm, src);
+					return new SpSetArgument(varTerm, src);
+				}
+				assignwarn("代入式に使用できない演算子が使われました", line, 2, false);
+				return null;
+			}
+		}
+				
+		private sealed class METHOD_ArgumentBuilder : ArgumentBuilder
+		{
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] args = popTerms(line);
+				string errmes = line.Function.Method.CheckArgumentType(line.Function.Name, args);
+				if (errmes != null)
+					throw new CodeEE(errmes);
+				IOperandTerm mTerm = new FunctionMethodTerm(line.Function.Method, args);
+				return new MethodArgument(mTerm.Restructure(exm));
+			}
+		}
+
+        private sealed class SP_INPUTS_ArgumentBuilder : ArgumentBuilder
+        {
+            public SP_INPUTS_ArgumentBuilder()
+            {
+                argumentTypeArray = new[] { typeof(string) };
+                //if (nullable)妥協
+                minArg = 0;
+            }
+            public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+            {
+                StringStream st = line.PopArgumentPrimitive();
+                Argument ret = null;
+                if (st.EOS)
+                {
+                    ret = new ExpressionArgument(null);
+                    return ret;
+                }
+                StrFormWord sfwt = LexicalAnalyzer.AnalyseFormattedString(st, FormStrEndWith.EoL, false);
+                if (!st.EOS)
+                {
+                    warn("Too many arguments", line, 1, false);
+                }
+                IOperandTerm term = ExpressionParser.ToStrFormTerm(sfwt);
+                term = term.Restructure(exm);
+                ret = new ExpressionArgument(term);
+                if (term is SingleTerm)
+                {
+                    ret.ConstStr = term.GetStrValue(exm);
+                    if (line.FunctionCode == FunctionCode.ONEINPUTS)
+                    {
+	                    if (string.IsNullOrEmpty(ret.ConstStr))
+                        {
+                            warn("引数が空文字列なため、引数は無視されます", line, 1, false);
+                            return new ExpressionArgument(null);
+                        }
+
+	                    if (ret.ConstStr.Length > 1)
+	                    {
+		                    warn("ONEINPUTSの引数に2文字以上の文字列が渡されています(2文字目以降は無視されます)", line, 1, false);
+		                    ret.ConstStr = ret.ConstStr.Remove(1);
+	                    }
+                    }
+                    ret.IsConst = true;
+                }
+                return ret;
+            }
+        }
+        
+		#region 正規型 popTerms()とcheckArgumentType()を両方行うもの。考えることは最低限でよい。
+
+		private sealed class INT_EXPRESSION_ArgumentBuilder : ArgumentBuilder
+		{
+			public INT_EXPRESSION_ArgumentBuilder(bool nullable)
+			{
+				argumentTypeArray = new[] { typeof(Int64) };
+				//if (nullable)妥協
+				minArg = 0;
+				this.nullable = nullable;
+			}
+			bool nullable;
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+				IOperandTerm term = null;
+				if (terms.Length == 0)
+				{
+					term = new SingleTerm(0);
+					if (!nullable)
+					{
+						if (line.Function.IsExtended())
+							warn("Arguments that cannot be omitted were omitted.\nEmuera will add 0.", line, 1, false);
+						else
+							warn("Arguments that cannot be omitted were omitted.\nEmuera adds 0, but the behavior of eramaker is undefined.", line, 1, false);
+					}
+				}
+				else
+				{
+					term = terms[0];
+				}
+				
+				if (line.FunctionCode == FunctionCode.REPEAT)
+				{
+					if ((term is SingleTerm) && (term.GetIntValue(null) <= 0L))
+					{
+						warn("REPEAT of 0 times or less has been detected (eramaker will throw an error)", line, 0, true);
+					}
+					VariableToken count = GlobalStatic.VariableData.GetSystemVariableToken("COUNT");
+					VariableTerm repCount = new VariableTerm(count, new IOperandTerm[] { new SingleTerm(0) });
+					repCount.Restructure(exm);
+					return new SpForNextArgment(repCount, new SingleTerm(0), term, new SingleTerm(1));
+				}
+				ExpressionArgument ret = new ExpressionArgument(term);
+				if (term is SingleTerm)
+				{
+					Int64 i = term.GetIntValue(null);
+					ret.ConstInt = i;
+					ret.IsConst = true;
+					if (line.FunctionCode == FunctionCode.CLEARLINE)
+					{
+						if (i <= 0L)
+							warn("A value less than or equal to 0 is passed as an argument (this line does nothing)", line, 1, false);
+					}
+					else if (line.FunctionCode == FunctionCode.FONTSTYLE)
+					{
+						if (i < 0L)
+							warn("A negative value is passed as an argument (the result is undefined)", line, 1, false);
+					}
+				}
+				return ret;
+			}
+		}
+
+		private sealed class INT_ANY_ArgumentBuilder : ArgumentBuilder
+		{
+			public INT_ANY_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(Int64) };
+				minArg = 0;
+				argAny = true;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+
+				List<IOperandTerm> termList = new List<IOperandTerm>();
+				termList.AddRange(terms);
+				ExpressionArrayArgument ret = new ExpressionArrayArgument(termList);
+				if (terms.Length == 0)
+				{
+					if (line.FunctionCode == FunctionCode.RETURN)
+					{
+						termList.Add(new SingleTerm(0));
+						ret.IsConst = true;
+						ret.ConstInt = 0;
+						return ret;
+					}
+					warn("Argument is not set", line, 2, false);
+					return null;
+				}
+
+				if (terms.Length == 1)
+				{
+
+					SingleTerm s = terms[0] as SingleTerm;
+					if (s != null)
+					{
+						ret.IsConst = true;
+						ret.ConstInt = s.Int;
+						return ret;
+					}
+
+					if (line.FunctionCode == FunctionCode.RETURN)
+					{
+						//定数式は定数化してしまうので現行システムでは見つけられない
+						if (terms[0] is VariableTerm)
+							warn("Variable is passed as argument to RETURN (eramaker: Always returns 0)", line, 0, true);
+						else
+							warn("A formula is passed as an argument to RETURN (eramaker: Emuera returns a different value)", line, 0, true);
+					}
+				}
+				else
+				{
+					warn(line.Function.Name + ": The arguments are given to more than one value. (eramaker: Not supported)", line, 0, true);
+				}
+				return ret;
+			}
+		}
+		
+		private sealed class STR_EXPRESSION_ArgumentBuilder : ArgumentBuilder
+		{
+			public STR_EXPRESSION_ArgumentBuilder(bool nullable)
+			{
+				argumentTypeArray = new[] { typeof(string) };
+				if (nullable)
+					minArg = 0;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+				ExpressionArgument ret = null;
+				if (terms.Length == 0)
+				{
+					ret = new ExpressionArgument(new SingleTerm(""));
+					ret.ConstStr = "";
+					ret.IsConst = true;
+					return ret;
+				}
+				return new ExpressionArgument(terms[0]);
+			}
+		}
+
+		private sealed class EXPRESSION_ArgumentBuilder : ArgumentBuilder
+		{
+			public EXPRESSION_ArgumentBuilder(bool nullable)
+			{
+				argumentTypeArray = new[] { typeof(void) };
+				if (nullable)
+					minArg = 0;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+				if (terms.Length == 0)
+				{
+					ExpressionArgument ret = new ExpressionArgument(null);
+					ret.ConstStr = "";
+					ret.ConstInt = 0;
+					ret.IsConst = true;
+					return ret;
+				}
+				return new ExpressionArgument(terms[0]);
+			}
+		}
+
+		private sealed class SP_BAR_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_BAR_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(Int64), typeof(Int64), typeof(Int64) };
+				//minArg = 3;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+				return new SpBarArgument(terms[0], terms[1], terms[2]);
+			}
+		}
+
+		private sealed class SP_SWAP_ArgumentBuilder : ArgumentBuilder
+		{
+            //emuera1803beta2+v1 第2引数省略型に対応
+			public SP_SWAP_ArgumentBuilder(bool nullable)
+			{
+				argumentTypeArray = new[] { typeof(Int64), typeof(Int64) };
+                if (nullable)
+                    minArg = 1;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+                //上の判定で省略不可時はここに来ないので即さばける
+                if (terms.Length == 1)
+                    terms = new[] { terms[0], null };
+				return new SpSwapCharaArgument(terms[0], terms[1]);
+			}
+		}
+
+        private sealed class SP_SAVEDATA_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_SAVEDATA_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(Int64), typeof(string) };
+			}
+
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+				return new SpSaveDataArgument(terms[0], terms[1]);
+			}
+		}
+
+        private sealed class SP_TINPUT_ArgumentBuilder : ArgumentBuilder
+        {
+            public SP_TINPUT_ArgumentBuilder()
+            {
+                argumentTypeArray = new[] { typeof(Int64), typeof(Int64), typeof(Int64), typeof(string) };
+                minArg = 2;
+            }
+            public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+            {
+                IOperandTerm[] terms = popTerms(line);
+                IOperandTerm term3 = null, term4 = null;
+                if (!checkArgumentType(line, exm, terms))
+                    return null;
+                if (terms.Length > 2)
+                    term3 = terms[2];
+                if (terms.Length > 3)
+                    term4 = terms[3];
+
+                return new SpTInputsArgument(terms[0], terms[1], term3, term4);
+            }
+        }
+        
+        private sealed class SP_TINPUTS_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_TINPUTS_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(Int64), typeof(string), typeof(Int64), typeof(string) };
+				minArg = 2;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+                IOperandTerm term3 = null, term4 = null;
+                if (!checkArgumentType(line, exm, terms))
+					return null;
+                if (terms.Length > 2)
+                    term3 = terms[2];
+                if (terms.Length > 3)
+                    term4 = terms[3];
+                return new SpTInputsArgument(terms[0], terms[1], term3, term4);
+			}
+		}
+
+		private sealed class SP_FOR_NEXT_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_FOR_NEXT_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(Int64), null, typeof(Int64), typeof(Int64) };
+				minArg = 3;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+				VariableTerm varTerm = getChangeableVariable(terms, 1, line);
+				if (varTerm == null)
+					return null;
+				if (varTerm.Identifier.IsCharacterData)
+				{ warn("The character variable cannot be specified as the first argument", line, 2, false); return null; }
+
+				IOperandTerm start = terms[1];
+				IOperandTerm end = terms[2];
+				IOperandTerm step = null;
+				if (start == null)
+					start = new SingleTerm(0);
+				if ((terms.Length > 3) && (terms[3] != null))
+					step = terms[3];
+				else
+					step = new SingleTerm(1);
+				if (!start.IsInteger)
+				{ warn("The type of the second argument is different", line, 2, false); return null; }
+				return new SpForNextArgment(varTerm, start, end, step);
+			}
+		}
+
+		private sealed class SP_POWER_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_POWER_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(Int64), typeof(Int64), typeof(Int64) };
+				//minArg = 2;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+				VariableTerm varTerm = getChangeableVariable(terms, 1, line);
+				if (varTerm == null)
+					return null;
+
+				return new SpPowerArgument(varTerm, terms[1], terms[2]);
+			}
+		}
+
+        private sealed class SP_SWAPVAR_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_SWAPVAR_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(void), typeof(void) };
+				//minArg = 2;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+				VariableTerm x = getChangeableVariable(terms, 1, line);
+				if (x == null)
+					return null;
+				VariableTerm y = getChangeableVariable(terms, 2, line);
+				if (y == null)
+					return null;
+				if (x.GetOperandType() != y.GetOperandType())
+				{
+					warn("Argument type is different", line, 2, false);
+					return null;
+				}
+				return new SpSwapVarArgument(x, y);
+			}
+		}
+		
+		private sealed class VAR_INT_ArgumentBuilder : ArgumentBuilder
+		{
+			public VAR_INT_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(Int64) };
+				minArg = 0;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (terms.Length == 0)
+					return new PrintDataArgument(null);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+				VariableTerm varTerm = getChangeableVariable(terms, 1, line);
+				if (varTerm == null)
+					return null;
+				return new PrintDataArgument(varTerm);
+			}
+		}
+
+        private sealed class VAR_STR_ArgumentBuilder : ArgumentBuilder
+        {
+            public VAR_STR_ArgumentBuilder()
+            {
+                argumentTypeArray = new[] { typeof(string) };
+                minArg = 0;
+            }
+            public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+            {
+                IOperandTerm[] terms = popTerms(line);
+                if (terms.Length == 0)
+                {
+                    VariableToken varToken = GlobalStatic.VariableData.GetSystemVariableToken("RESULTS");
+                    VariableTerm varTerm = new VariableTerm(varToken, new IOperandTerm[] { new SingleTerm(0) });
+                    return new StrDataArgument(varTerm);
+                }
+                if (!checkArgumentType(line, exm, terms))
+                    return null;
+                VariableTerm x = getChangeableVariable(terms, 1, line);
+                if (x == null)
+                    return null;
+                return new StrDataArgument(x);
+            }
+        }
+
+		private sealed class BIT_ARG_ArgumentBuilder : ArgumentBuilder
+		{
+			public BIT_ARG_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(Int64), typeof(Int64) };
+				minArg = 2;
+                argAny = true;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+                VariableTerm varTerm = getChangeableVariable(terms, 1, line);
+				if (varTerm == null)
+					return null;
+                List<IOperandTerm> termList = new List<IOperandTerm>();
+                termList.AddRange(terms);
+                //最初の項はいらない
+                termList.RemoveAt(0);
+				BitArgument ret = new BitArgument(varTerm, termList.ToArray());
+                for (int i = 0; i < termList.Count; i++)
+                {
+                    if (termList[i] is SingleTerm)
+                    {
+                        Int64 bit = ((SingleTerm)termList[i]).Int;
+                        if ((bit < 0) || (bit > 63))
+                        {
+                            warn("Argument number " + Strings.StrConv((i + 2).ToString(), VbStrConv.Wide, Config.Language) + " argument (" + bit + ") is outside the range (0 to 63)", line, 2, false);
+                            return null;
+                        }
+                    }
+                }
+				return ret;
+			}
+		}
+
+		private sealed class SP_VAR_SET_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_VAR_SET_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(void), typeof(void), typeof(Int64), typeof(Int64) };
+				minArg = 1;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+				VariableTerm varTerm = getChangeableVariable(terms, 1, line);
+				if (varTerm == null)
+					return null;
+                if (varTerm.Identifier.IsConst)
+                {
+					warn("A variable that cannot change its value " + varTerm.Identifier.Name + " has a specified value", line, 2, false);
+                    return null;
+                }
+
+				IOperandTerm term, term3 = null, term4 = null;
+				if (terms.Length > 1)
+					term = terms[1];
+				else
+				{
+					if (varTerm.IsString)
+						term = new SingleTerm("");
+					else
+						term = new SingleTerm(0);
+				}
+				if (varTerm is VariableNoArgTerm)
+				{
+					if (terms.Length > 2)
+					{
+						warn("対象となる変数" + varTerm.Identifier.Name + "の要素を省略する場合には第3引数以降を設定できません", line, 2, false);
+						return null;
+					}
+					return new SpVarSetArgument(new FixedVariableTerm(varTerm.Identifier), term, null, null);
+				}
+				if (terms.Length > 2)
+					term3 = terms[2];
+				if (terms.Length > 3)
+					term4 = terms[3];
+				if (terms.Length >= 3 && !varTerm.Identifier.IsArray1D)
+					warn("第3引数以降は1次元配列以外では無視されます", line, 1, false);
+				if (term.GetOperandType() != varTerm.GetOperandType())
+				{
+					warn("2つの引数の型が一致していません", line, 2, false);
+					return null;
+				}
+				return new SpVarSetArgument(varTerm, term, term3, term4);
+			}
+		}
+
+		private sealed class SP_CVAR_SET_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_CVAR_SET_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(void), typeof(void), typeof(void), typeof(Int64), typeof(Int64) };
+				minArg = 1;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+
+				VariableTerm varTerm = getChangeableVariable(terms, 1, line);
+				if (varTerm == null)
+					return null;
+				if (!varTerm.Identifier.IsCharacterData)
+				{ warn("第1引数にキャラクタ変数以外の変数を指定することはできません", line, 2, false); return null; }
+				//1803beta004 暫定CDFLAGを弾く
+				if (varTerm.Identifier.IsArray2D)
+				{ warn("第1引数に二次元配列の変数を指定することはできません", line, 2, false); return null; }
+				IOperandTerm index, term, term4 = null, term5 = null;
+				if (terms.Length > 1)
+					index = terms[1];
+				else
+					index = new SingleTerm(0);
+				if (terms.Length > 2)
+					term = terms[2];
+				else
+				{
+					if (varTerm.IsString)
+						term = new SingleTerm("");
+					else
+						term = new SingleTerm(0);
+				}
+				if (terms.Length > 3)
+					term4 = terms[3];
+				if (terms.Length > 4)
+					term5 = terms[4];
+				if (index is SingleTerm && index.GetOperandType() == typeof(string) && varTerm.Identifier.IsArray1D)
+				{
+					if (!GlobalStatic.ConstantData.isDefined(varTerm.Identifier.Code, ((SingleTerm)index).Str))
+					{ warn("文字列" + index.GetStrValue(null) + "は変数" + varTerm.Identifier.Name + "の要素ではありません", line, 2, false); return null; }
+				}
+				if (terms.Length > 3 && !varTerm.Identifier.IsArray1D)
+					warn("The fourth and subsequent arguments are ignored except for one-dimensional arrays", line, 1, false);
+				if (term.GetOperandType() != varTerm.GetOperandType())
+				{
+					warn("The types of the two arguments do not match", line, 2, false);
+					return null;
+				}
+				return new SpCVarSetArgument(varTerm, index, term, term4, term5);
+			}
+		}
+
+		private sealed class SP_BUTTON_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_BUTTON_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(string), typeof(void) };
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+				return new SpButtonArgument(terms[0], terms[1]);
+			}
+		}
+
+		private sealed class SP_COLOR_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_COLOR_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(Int64), typeof(Int64), typeof(Int64) };
+				minArg = 1;
+			}
+
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+                if (terms.Length == 2)
+                { warn("The number of arguments of SETCOLOR is invalid (SETCOLOR takes only 1 or 3 arguments)", line, 2, false); return null; }
+                SpColorArgument arg = null;
+                if (terms.Length == 1)
+                {
+                    arg = new SpColorArgument(terms[0]);
+                    if (terms[0] is SingleTerm)
+                    {
+                        arg.ConstInt = terms[0].GetIntValue(exm);
+                        arg.IsConst = true;
+                    }
+                }
+                else
+                {
+                    arg = new SpColorArgument(terms[0], terms[1], terms[2]);
+                    if ((terms[0] is SingleTerm) && (terms[1] is SingleTerm) && (terms[2] is SingleTerm))
+                    {
+                        arg.ConstInt = (terms[0].GetIntValue(exm) << 16) + (terms[1].GetIntValue(exm) << 8) + (terms[2].GetIntValue(exm));
+                        arg.IsConst = true;
+                    }
+                }
+                return arg;
+			}
+		}
+
+		private sealed class SP_SPLIT_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_SPLIT_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(string), typeof(string), typeof(string), typeof(Int64) };
+				minArg = 3;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+				VariableTerm x = getChangeableVariable(terms, 3, line);
+				if (x == null)
+					return null;
+				if (!x.Identifier.IsArray1D && !x.Identifier.IsArray2D && !x.Identifier.IsArray3D)
+				{ warn("The third argument must be an array variable", line, 2, false); return null; }
+                VariableTerm term = (terms.Length >= 4) ? getChangeableVariable(terms, 4, line) : new VariableTerm(GlobalStatic.VariableData.GetSystemVariableToken("RESULT"), new IOperandTerm[]{new SingleTerm(0)});
+				return new SpSplitArgument(terms[0], terms[1], x.Identifier, term);
+			}
+		}
+		
+		private sealed class SP_HTMLSPLIT_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_HTMLSPLIT_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(string), typeof(string), typeof(Int64) };
+				minArg = 1;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+				VariableToken destVar = null;
+				VariableTerm destVarTerm = null;
+				VariableTerm term = null;
+				if (terms.Length >= 2)
+					destVarTerm = getChangeableVariable(terms, 2, line);
+				if (destVarTerm != null)
+					destVar = destVarTerm.Identifier;
+				else
+					destVar = GlobalStatic.VariableData.GetSystemVariableToken("RESULTS");
+				if (!destVar.IsArray1D || destVar.IsCharacterData)
+				{ warn("第2引数は非キャラ型の1次元配列変数でなければなりません", line, 2, false); return null; }
+				if (terms.Length >= 3)
+					term = getChangeableVariable(terms, 3, line);
+				if (term == null)
+				{
+                    VariableToken varToken = GlobalStatic.VariableData.GetSystemVariableToken("RESULT");
+                    term = new VariableTerm(varToken, new IOperandTerm[] { new SingleTerm(0) });
+				}
+				return new SpHtmlSplitArgument(terms[0], destVar, term);
+			}
+		}
+		
+		private sealed class SP_GETINT_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_GETINT_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(Int64) };
+				minArg = 0;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (terms.Length == 0)
+				{
+					VariableToken varToken = GlobalStatic.VariableData.GetSystemVariableToken("RESULT");
+					return new SpGetIntArgument(new VariableTerm(varToken, new IOperandTerm[]{new SingleTerm(0)}));
+				}
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+				VariableTerm x = getChangeableVariable(terms, 1, line);
+				if (x == null)
+					return null;
+				return new SpGetIntArgument(x);
+			}
+		}
+
+		private sealed class SP_CONTROL_ARRAY_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_CONTROL_ARRAY_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(void), typeof(Int64), typeof(Int64) };
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+				VariableTerm x = getChangeableVariable(terms, 1, line);
+				if (x == null)
+					return null;
+				return new SpArrayControlArgument(x, terms[1], terms[2]);
+			}
+		}
+
+		private sealed class SP_SHIFT_ARRAY_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_SHIFT_ARRAY_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(void), typeof(Int64), typeof(void), typeof(Int64), typeof(Int64) };
+				minArg = 3;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+
+				VariableTerm x = getChangeableVariable(terms, 1, line);
+				if (x == null)
+					return null;
+				if (!x.Identifier.IsArray1D)
+				{ warn("第1引数に1次元配列もしくは配列型キャラクタ変数以外を指定することはできません", line, 2, false); return null; }
+
+				if (line.FunctionCode == FunctionCode.ARRAYSHIFT)
+				{
+					if (terms[0].GetOperandType() != terms[2].GetOperandType())
+					{ warn("First and third argument types are different", line, 2, false); return null; }
+				}
+				IOperandTerm term4 = terms.Length >= 4 ? terms[3] : new SingleTerm(0);
+				IOperandTerm term5 = terms.Length >= 5 ? terms[4] : null;
+				return new SpArrayShiftArgument(x, terms[1], terms[2], term4, term5);
+			}
+		}
+
+		private sealed class SP_SAVEVAR_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_SAVEVAR_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(string), typeof(string), typeof(void)};
+				argAny = true;
+				minArg = 3;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+				List<VariableToken> varTokens = new List<VariableToken>();
+				for (int i = 2; i < terms.Length; i++)
+				{
+					if (terms[i] == null)
+					{ warn("第" + (i + 1) + "引数を省略できません", line, 2, false); return null; }
+					VariableTerm vTerm = getChangeableVariable(terms, i + 1, line);
+					if (vTerm == null)
+						return null;
+					VariableToken vToken = vTerm.Identifier;
+					if (vToken.IsCharacterData)
+					{ warn("キャラクタ変数"+ vToken.Name+"はセーブできません(キャラクタ変数のSAVEにはSAVECHARAを使用します)", line, 2, false); return null; }
+					if (vToken.IsPrivate)
+					{ warn("プライベート変数" + vToken.Name + "はセーブできません", line, 2, false); return null; }
+					if (vToken.IsLocal)
+					{ warn("ローカル変数" + vToken.Name + "はセーブできません", line, 2, false); return null; }
+					if (vToken.IsConst)
+					{ warn("値を変更できない変数はセーブできません", line, 2, false); return null; }
+					if (vToken.IsCalc)
+					{ warn("疑似変数はセーブできません", line, 2, false); return null; }
+					if (vToken.IsReference)
+					{ warn("参照型変数はセーブできません", line, 2, false); return null; }
+					varTokens.Add(vToken);
+				}
+				for (int i = 0; i < varTokens.Count; i++)
+				{
+					for (int j = i + 1; j < varTokens.Count; j++)
+						if (varTokens[i] == varTokens[j])
+						{
+							warn("変数" + varTokens[i].Name + "を二度以上保存しようとしています", line, 1, false);
+							return null;
+						}
+				}
+				VariableToken[] arg3 = new VariableToken[varTokens.Count];
+				varTokens.CopyTo(arg3);
+				return new SpSaveVarArgument(terms[0], terms[1], arg3);
+			}
+		}
+
+		private sealed class SP_SAVECHARA_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_SAVECHARA_ArgumentBuilder()
+			{
+				argumentTypeArray = new[] { typeof(string), typeof(string), typeof(Int64) };
+				minArg = 3;
+				argAny = true;
+			}
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				IOperandTerm[] terms = popTerms(line);
+				if (!checkArgumentType(line, exm, terms))
+					return null;
+
+				List<IOperandTerm> termList = new List<IOperandTerm>();
+				termList.AddRange(terms);
+				ExpressionArrayArgument ret = new ExpressionArrayArgument(termList);
+
+				for (int i = 2; i < termList.Count; i++)
+				{
+					if (!(termList[i] is SingleTerm))
+						continue;
+					Int64 iValue = termList[i].GetIntValue(null);
+					if (iValue < 0)
+					{ warn("Character registration number must be a positive value", line, 2, false); return null; }
+					if (iValue > Int32.MaxValue)
+					{ warn("Character registration number exceeds the upper limit of the 32 bit signed integer", line, 2, false); return null; }
+					for (int j = i + 1; j < termList.Count; j++)
+					{
+						if (!(termList[j] is SingleTerm))
+							continue;
+						if (iValue == termList[j].GetIntValue(null))
+						{
+							warn("Character registration number " + iValue + " is being saved more than once", line, 1, false);
+							return null;
+						}
+					}
+				}
+				return ret;
+			}
+		}
+
+		private sealed class SP_REF_ArgumentBuilder : ArgumentBuilder
+		{
+			public SP_REF_ArgumentBuilder(bool byname)
+			{
+				argumentTypeArray = new[] { typeof(void), typeof(void) };
+				minArg = 2;
+				this.byname = byname;
+			}
+			bool byname;
+			public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+			{
+				WordCollection wc = popWords(line);
+				IdentifierWord id = wc.Current as IdentifierWord;
+				wc.ShiftNext();
+				if (id == null || wc.Current.Type != ',')
+				{ warn("The format is wrong", line, 2, false); return null; }
+				wc.ShiftNext();
+				IOperandTerm name = null;
+				IdentifierWord id2 = null;
+				string srcCode = null;
+				if (byname)
+				{
+					name = ExpressionParser.ReduceExpressionTerm(wc, TermEndWith.EoL);
+					if (name == null || name.IsInteger || !wc.EOL)
+					{ warn("The format is wrong", line, 2, false); return null; }
+					name = name.Restructure(exm);
+					if (name is SingleTerm)
+						srcCode = name.GetStrValue(exm);
+				}
+				else
+				{
+					id2 = wc.Current as IdentifierWord;
+					wc.ShiftNext();
+					if (id2 == null || !wc.EOL)
+					{ warn("The format is wrong", line, 2, false); return null; }
+					srcCode = id2.Code;
+				}
+				UserDefinedRefMethod refm = GlobalStatic.IdentifierDictionary.GetRefMethod(id.Code);
+				ReferenceToken refVar = null;
+				if (refm == null)
+				{
+					VariableToken token = GlobalStatic.IdentifierDictionary.GetVariableToken(id.Code, null, true);
+					if (token == null || !token.IsReference)
+					{ warn("The first argument must be a function reference or a reference type variable", line, 2, false); return null; }
+					refVar = (ReferenceToken)token;
+				}
+
+				if (refm != null)
+				{
+					if (srcCode == null)
+						return new RefArgument(refm, name);
+					UserDefinedRefMethod srcRef = GlobalStatic.IdentifierDictionary.GetRefMethod(srcCode);
+					if (srcRef != null)
+					{
+						return new RefArgument(refm, srcRef);
+					}
+					FunctionLabelLine label = GlobalStatic.LabelDictionary.GetNonEventLabel(srcCode);
+					if (label == null)
+					{ warn("Function " + srcCode + " is missing", line, 2, false); return null; }
+					if (!label.IsMethod)
+					{ warn("Cannot refer to functions without #FUNCTION(S) attribute" + srcCode, line, 2, false); return null; }
+					CalledFunction called = CalledFunction.CreateCalledFunctionMethod(label, label.LabelName);
+					return new RefArgument(refm, called);
+				}
+
+				if (srcCode == null)
+					return new RefArgument(refVar, name);
+				VariableToken srcVar = GlobalStatic.IdentifierDictionary.GetVariableToken(srcCode, null, true);
+				if (srcVar == null)
+				{ warn("Variable " + srcCode + " is missing", line, 2, false); return null; }
+				return new RefArgument(refVar, srcVar);
+			}
+		}
+
+        private sealed class SP_INPUT_ArgumentBuilder : ArgumentBuilder
+        {
+            public SP_INPUT_ArgumentBuilder()
+            {
+                argumentTypeArray = new[] { typeof(Int64) };
+                //if (nullable)妥協
+                minArg = 0;
+            }
+            public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+            {
+                IOperandTerm[] terms = popTerms(line);
+                if (!checkArgumentType(line, exm, terms))
+                    return null;
+                IOperandTerm term = null;
+                ExpressionArgument ret;
+                if (terms.Length == 0)
+                {
+                    ret = new ExpressionArgument(term);
+                    return ret;
+                }
+
+	            term = terms[0];
+	            ret = new ExpressionArgument(term);
+
+	            if (term is SingleTerm)
+                {
+                    Int64 i = term.GetIntValue(null);
+                    if (line.FunctionCode == FunctionCode.ONEINPUT)
+                    {
+	                    if (i < 0)
+                        {
+                            warn("ONEINPUTの引数にONEINPUTが受け取れない負の数数が指定されています(引数を無効とします)", line, 1, false);
+                            ret = new ExpressionArgument(null);
+                            return ret;
+                        }
+
+	                    if (i > 9)
+	                    {
+		                    warn("ONEINPUTの引数にONEINPUTが受け取れない2桁以上の数数が指定されています(最初の桁を引数と見なします)", line, 1, false);
+		                    i = Int64.Parse(i.ToString().Remove(1));
+	                    }
+                    }
+                    ret.ConstInt = i;
+                    ret.IsConst = true;
+                }
+                return ret;
+            }
+        }
+
+        private sealed class SP_COPY_ARRAY_Arguments : ArgumentBuilder
+        {
+            public SP_COPY_ARRAY_Arguments()
+            {
+                argumentTypeArray = new[] { typeof(string), typeof(string) };
+                minArg = 2;
+            }
+
+            public override Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+            {
+                IOperandTerm[] terms = popTerms(line);
+                if (!checkArgumentType(line, exm, terms))
+                    return null;
+                VariableToken[] vars = new VariableToken[2] { null, null };
+                if (terms[0] is SingleTerm)
+                {
+                    if ((vars[0] = GlobalStatic.IdentifierDictionary.GetVariableToken(((SingleTerm)terms[0]).Str, null, true)) == null)
+                    {
+                        warn("ARRAYCOPY命令の第1引数\"" + ((SingleTerm)terms[0]).Str + "\"は変数名として存在しません", line, 2, false);
+                        return null;
+                    }
+                    if (!vars[0].IsArray1D && !vars[0].IsArray2D && !vars[0].IsArray3D)
+                    {
+                        warn("ARRAYCOPY命令の第1引数\"" + ((SingleTerm)terms[0]).Str + "\"は配列変数ではありません", line, 2, false);
+                        return null;
+                    }
+                    if (vars[0].IsCharacterData)
+                    {
+                        warn("ARRAYCOPY命令の第1引数\"" + ((SingleTerm)terms[0]).Str + "\"はキャラクタ変数です(対応していません)", line, 2, false);
+                        return null;
+                    }
+                }
+                if (terms[1] is SingleTerm)
+                {
+                    if ((vars[1] = GlobalStatic.IdentifierDictionary.GetVariableToken(((SingleTerm)terms[1]).Str, null, true)) == null)
+                    {
+                        warn("ARRAYCOPY命令の第2引数\"" + ((SingleTerm)terms[1]).Str + "\"は変数名として存在しません", line, 2, false);
+                        return null;
+                    }
+                    if (!vars[1].IsArray1D && !vars[1].IsArray2D && !vars[1].IsArray3D)
+                    {
+                        warn("ARRAYCOPY命令の第2引数\"" + ((SingleTerm)terms[1]).Str + "\"は配列変数ではありません", line, 2, false);
+                    }
+                    if (vars[1].IsCharacterData)
+                    {
+                        warn("ARRAYCOPY命令の第2引数\"" + ((SingleTerm)terms[1]).Str + "\"はキャラクタ変数です(対応していません)", line, 2, false);
+                        return null;
+                    }
+                    if (vars[1].IsConst)
+                    {
+                        warn("ARRAYCOPY命令の第2引数\"" + ((SingleTerm)terms[1]).Str + "\"は値を変更できない変数です", line, 2, false);
+                        return null;
+                    }
+                }
+                if ((vars[0] != null) && (vars[1] != null))
+                {
+                    if ((vars[0].IsArray1D && !vars[1].IsArray1D) || (vars[0].IsArray2D && !vars[1].IsArray2D) || (vars[0].IsArray3D && !vars[1].IsArray3D))
+                    {
+                        warn("ARRAYCOPY命令の2つの引数の次元が異なります", line, 2, false);
+                        return null;
+                    }
+                    if ((vars[0].IsInteger && vars[1].IsString) || (vars[0].IsString && vars[1].IsInteger))
+                    {
+                        warn("ARRAYCOPY命令の2つの配列変数の型が一致していません", line, 2, false);
+                        return null;
+                    }
+                }
+                return new SpCopyArrayArgument(terms[0], terms[1]);
+            }
+        }
+        #endregion		
+	}
+}

+ 57 - 0
NTERA/Game/GameProc/Function/ArgumentParser.cs

@@ -0,0 +1,57 @@
+using System.Media;
+using MinorShift.Emuera.Sub;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera.GameProc.Function
+{
+	//1756 LogicalLineParserから分離。処理をArgumentBuilderに分割
+	internal static partial class ArgumentParser
+	{
+		public static bool SetArgumentTo(InstructionLine line)
+		{
+			if (line == null)
+				return false;
+			if (line.Argument != null)
+				return true;
+			if (line.IsError)
+				return false;
+			if (!Program.DebugMode && line.Function.IsDebug())
+			{//非DebugモードでのDebug系命令。何もしないので引数解析も不要
+				line.Argument = null;
+				return true;
+			}
+
+			Argument arg = null;
+			string errmes = null;
+			try
+			{
+				arg = line.Function.ArgBuilder.CreateArgument(line, GlobalStatic.EMediator);
+			}
+			catch (EmueraException e)
+			{
+				errmes = e.Message;
+				goto error;
+			}
+			if (arg == null)
+			{
+				if (!line.IsError)
+				{
+					errmes = "命令の引数解析中に特定できないエラーが発生";
+					goto error;
+				}
+				return false;
+			}
+			line.Argument = arg;
+			if (arg == null)
+				line.IsError = true;
+			return true;
+		error:
+			SystemSounds.Hand.Play();
+
+			line.IsError = true;
+			line.ErrMes = errmes;
+			ParserMediator.Warn(errmes, line, 2, true, false);
+			return false;
+		}
+	}
+}

+ 360 - 0
NTERA/Game/GameProc/Function/BuiltInFunctionCode.cs

@@ -0,0 +1,360 @@
+
+using System.Reflection;
+
+namespace MinorShift.Emuera.GameProc.Function
+{
+	/// <summary>
+	/// 命令コード
+	/// </summary>
+	//難読化用属性。enum.ToString()やenum.Parse()を行うなら(Exclude=true)にすること。
+	[Obfuscation(Exclude = true)]
+	enum FunctionCode
+	{//数値不要
+		//FunctionCodeを定義したらstatic FunctionIdentifier()内でaddFunctionすること。
+		//その際に適切なFunctionArgとフラグを選ぶ。
+
+		//FunctionMethod(式中関数)を定義した場合には自動で拾うので何もしなくてよい。
+		//ただし、式中関数バージョンと命令バージョンで動作が違うなら追加する必要がある。
+
+		__NULL__ = 0x0000,
+		SET,//数値代入文 or 文字列代入文
+		//SETS,//文字列代入文
+		PRINT,//文字を表示する
+		PRINTL,//改行
+		PRINTW,//入力待ち(実質改行)
+
+		PRINTV,//変数の内容
+		PRINTVL,
+		PRINTVW,
+
+		PRINTS,//文字列変数の内容
+		PRINTSL,
+		PRINTSW,
+
+		PRINTFORM,//{数式}、%文字列変数%などの書式が使える。
+		PRINTFORML,
+		PRINTFORMW,
+
+		PRINTFORMS,//文字列変数の内容を変換して表示。
+		PRINTFORMSL,
+		PRINTFORMSW,
+
+		PRINTC,//??
+
+		CLEARLINE,
+		REUSELASTLINE,
+
+		WAIT,//改行待ち。
+		INPUT,//整数入力。入力はRESULTへ。
+		INPUTS,//文字列入力。入力はRESULTSへ。
+		TINPUT,
+		TINPUTS,
+		TWAIT,
+		WAITANYKEY,
+		FORCEWAIT,//スキップで省略できないWAIT、強制TWAITと違い、スキップを打ち切る
+		ONEINPUT,
+		ONEINPUTS,
+		TONEINPUT,
+		TONEINPUTS,
+
+		DRAWLINE,//画面の左端から右端まで----と線を引く。
+		BAR,//[*****....]のようなグラフを書く。BAR (変数) , (最大値), (長さ)
+		BARL,//改行付き。
+		TIMES,//小数計算。TIMES (変数) , (小数値)という形で使う。
+
+		PRINT_ABL,//能力。引数は登録番号
+		PRINT_TALENT,//素質
+		PRINT_MARK,//刻印
+		PRINT_EXP,//経験
+		PRINT_PALAM,//パラメータ
+		PRINT_ITEM,//所持アイテム
+		PRINT_SHOPITEM,//ショップで売っているアイテム
+
+		UPCHECK,//パラメータの変動
+		CUPCHECK,
+		ADDCHARA,//(キャラ番号)のキャラクタを追加
+		ADDSPCHARA,//(キャラ番号)のSPキャラクタを追加(フラグ0を1にして作成)
+		ADDDEFCHARA,
+		ADDVOIDCHARA,//変数に何の設定のないキャラを作成
+		DELCHARA,//(キャラ登録番号)のキャラクタを削除。
+
+		PUTFORM,//@SAVEINFO関数でのみ使用可能。PRINTFORMと同様の書式でセーブデータに概要をつける。
+		QUIT,//ゲームを終了
+		OUTPUTLOG,
+
+		BEGIN,//システム関数の実行。実行するとCALLの呼び出し元などを忘れてしまう。
+
+		SAVEGAME,//セーブ画面を呼ぶ。ショップのみ。
+		LOADGAME,//
+
+		SIF,//一行のみIF
+		IF,
+		ELSE,
+		ELSEIF,
+		ENDIF,
+
+		REPEAT,//RENDまで繰り返し。繰り返した回数がCOUNTへ。ネスト不可。
+		REND,
+		CONTINUE,//REPEATに戻る
+		BREAK,//RENDの次の行まで
+
+		GOTO,//$ラベルへジャンプ
+
+		JUMP,//関数に移動
+		CALL,//関数に移動。移動元を記憶し、RETURNで帰る。
+		CALLEVENT,
+		RETURN,//__INT_EXPRESSION__,//関数の終了。RESULTに整数を格納可能。省略した場合、0。(次の@~~がRETURNと見なされる。)  
+		RETURNFORM,//__FORM_STR__,//関数の終了。RESULTに整数を格納可能。省略した場合、0。(次の@~~がRETURNと見なされる。)  
+		RETURNF,
+		RESTART,//関数の再開。関数の最初に戻る。
+
+
+		STRLEN,
+		//STRLENS,//
+		STRLENFORM,
+		STRLENU,
+		//STRLENSU,
+		STRLENFORMU,
+
+		PRINTLC,
+		PRINTFORMC,
+		PRINTFORMLC,
+
+		SWAPCHARA,
+		COPYCHARA,
+		ADDCOPYCHARA,
+		VARSIZE,//動作が違うので__METHOD__化できない
+		SPLIT,
+
+		PRINTSINGLE,
+		PRINTSINGLEV,
+		PRINTSINGLES,
+		PRINTSINGLEFORM,
+		PRINTSINGLEFORMS,
+
+		PRINTBUTTON,
+		PRINTBUTTONC,
+		PRINTBUTTONLC,
+
+		PRINTPLAIN,
+		PRINTPLAINFORM,
+
+		SAVEDATA,
+		LOADDATA,
+		DELDATA,
+		GETTIME,//2つに代入する必要があるので__METHOD__化できない
+
+		TRYJUMP,
+		TRYCALL,
+		TRYGOTO,
+		JUMPFORM,
+		CALLFORM,
+		GOTOFORM,
+		TRYJUMPFORM,
+		TRYCALLFORM,
+		TRYGOTOFORM,
+		CALLTRAIN,
+		STOPCALLTRAIN,
+		CATCH,
+		ENDCATCH,
+		TRYCJUMP,
+		TRYCCALL,
+		TRYCGOTO,
+		TRYCJUMPFORM,
+		TRYCCALLFORM,
+		TRYCGOTOFORM,
+		TRYCALLLIST,
+		TRYJUMPLIST,
+		TRYGOTOLIST,
+		FUNC,
+		ENDFUNC,
+		CALLF,
+		CALLFORMF,
+
+		SETCOLOR,
+		SETCOLORBYNAME,
+		RESETCOLOR,
+		SETBGCOLOR,
+		SETBGCOLORBYNAME,
+		RESETBGCOLOR,
+		FONTBOLD,
+		FONTITALIC,
+		FONTREGULAR,
+		SORTCHARA,
+		FONTSTYLE,
+		ALIGNMENT,
+		CUSTOMDRAWLINE,
+		DRAWLINEFORM,
+		CLEARTEXTBOX,
+
+		SETFONT,
+
+		FOR,
+		NEXT,
+		WHILE,
+		WEND,
+
+		POWER,//引数が違うのでMETHOD化できない。
+		SAVEGLOBAL,
+		LOADGLOBAL,
+		SWAP,
+
+		RESETDATA,
+		RESETGLOBAL,
+
+		RANDOMIZE,
+		DUMPRAND,
+		INITRAND,
+
+		REDRAW,
+		DOTRAIN,
+
+		SELECTCASE,
+		CASE,
+		CASEELSE,
+		ENDSELECT,
+
+		DO,
+		LOOP,
+
+		PRINTDATA,
+		PRINTDATAL,
+		PRINTDATAW,
+		DATA,
+		DATAFORM,
+		ENDDATA,
+		DATALIST,
+		ENDLIST,
+		STRDATA,
+
+		PRINTCPERLINE,//よく考えたら引数の仕様違うや
+
+
+		SETBIT,
+		CLEARBIT,
+		INVERTBIT,
+		DELALLCHARA,
+		PICKUPCHARA,
+
+		VARSET,
+		CVARSET,
+
+		RESET_STAIN,
+
+		SAVENOS,//引数の仕様が違うので(ry
+
+		FORCEKANA,
+
+		SKIPDISP,
+		NOSKIP,
+		ENDNOSKIP,
+
+		ARRAYSHIFT,
+		ARRAYREMOVE,
+		ARRAYSORT,
+		ARRAYCOPY,
+
+		ENCODETOUNI,
+
+		DEBUGPRINT,
+		DEBUGPRINTL,
+		DEBUGPRINTFORM,
+		DEBUGPRINTFORML,
+		DEBUGCLEAR,
+		ASSERT,
+		THROW,
+
+		SAVEVAR,
+		LOADVAR,
+		//		CHKVARDATA,
+		SAVECHARA,
+		LOADCHARA,
+		//		CHKCHARADATA,
+
+		REF,
+		REFBYNAME,
+
+		PRINTK,
+		PRINTKL,
+		PRINTKW,
+
+		PRINTVK,//変数の内容
+		PRINTVKL,
+		PRINTVKW,
+
+		PRINTSK,//文字列変数の内容
+		PRINTSKL,
+		PRINTSKW,
+
+		PRINTFORMK,//{数式}、%文字列変数%などの書式が使える。
+		PRINTFORMKL,
+		PRINTFORMKW,
+
+		PRINTFORMSK,//文字列変数の内容を変換して表示。
+		PRINTFORMSKL,
+		PRINTFORMSKW,
+
+		PRINTCK,//??
+		PRINTLCK,
+		PRINTFORMCK,
+		PRINTFORMLCK,
+
+		PRINTSINGLEK,
+		PRINTSINGLEVK,
+		PRINTSINGLESK,
+		PRINTSINGLEFORMK,
+		PRINTSINGLEFORMSK,
+
+		PRINTDATAK,
+		PRINTDATAKL,
+		PRINTDATAKW,
+
+		PRINTD,//文字を表示する
+		PRINTDL,//改行
+		PRINTDW,//入力待ち(実質改行)
+
+		PRINTVD,//変数の内容
+		PRINTVDL,
+		PRINTVDW,
+
+		PRINTSD,//文字列変数の内容
+		PRINTSDL,
+		PRINTSDW,
+
+		PRINTFORMD,//{数式}、%文字列変数%などの書式が使える。
+		PRINTFORMDL,
+		PRINTFORMDW,
+
+		PRINTFORMSD,//文字列変数の内容を変換して表示。
+		PRINTFORMSDL,
+		PRINTFORMSDW,
+
+		PRINTCD,//??
+		PRINTLCD,
+		PRINTFORMCD,
+		PRINTFORMLCD,
+
+		PRINTSINGLED,
+		PRINTSINGLEVD,
+		PRINTSINGLESD,
+		PRINTSINGLEFORMD,
+		PRINTSINGLEFORMSD,
+
+		PRINTDATAD,
+		PRINTDATADL,
+		PRINTDATADW,
+
+		HTML_PRINT,
+        HTML_PRINTSL,
+        HTML_TAGSPLIT,
+
+		TOOLTIP_SETCOLOR,
+		TOOLTIP_SETDELAY,
+	        TOOLTIP_SETDURATION,
+
+		PRINT_IMG,
+		PRINT_RECT,
+		PRINT_SPACE
+
+	}
+}

+ 158 - 0
NTERA/Game/GameProc/Function/CircularBuffer.cs

@@ -0,0 +1,158 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace MinorShift.Emuera.GameProc.Function
+{
+    public interface ICircularBuffer<T>
+    {
+        int Count { get; }
+        int Capacity { get; set; }
+        T Enqueue(T item);
+        T Dequeue();
+        void Clear();
+        T this[int index] { get; set; }
+        int IndexOf(T item);
+        void Insert(int index, T item);
+        void RemoveAt(int index);
+    }
+
+    public class CircularBuffer<T> : ICircularBuffer<T>, IEnumerable<T>
+
+    {
+        private T[] _buffer;
+        private int _head;
+        private int _tail;
+
+        public CircularBuffer(int capacity)
+        {
+            if (capacity < 0)
+                throw new ArgumentOutOfRangeException("capacity", "must be positive");
+            _buffer = new T[capacity];
+            _head = capacity - 1;
+        }
+
+        public int Count { get; private set; }
+
+        public int Capacity
+        {
+            get => _buffer.Length;
+	        set
+            {
+                if (value < 0)
+                    throw new ArgumentOutOfRangeException("value", "must be positive");
+
+                if (value == _buffer.Length)
+                    return;
+
+                var buffer = new T[value];
+                var newCount = 0;
+                while (Count > 0 && newCount < value)
+                    buffer[newCount++] = Dequeue();
+
+                _buffer = buffer;
+                Count = newCount;
+                _head = newCount - 1;
+                _tail = 0;
+            }
+        }
+
+        public T Enqueue(T item)
+        {
+            _head = (_head + 1) % Capacity;
+            var overwritten = _buffer[_head];
+            _buffer[_head] = item;
+            if (Count == Capacity)
+                _tail = (_tail + 1) % Capacity;
+            else
+                ++Count;
+            return overwritten;
+        }
+
+        public T Dequeue()
+        {
+            if (Count == 0)
+                throw new InvalidOperationException("queue exhausted");
+
+            var dequeued = _buffer[_tail];
+            _buffer[_tail] = default(T);
+            _tail = (_tail + 1) % Capacity;
+            --Count;
+            return dequeued;
+        }
+
+        public void Clear()
+        {
+            _head = Capacity - 1;
+            _tail = 0;
+            Count = 0;
+        }
+
+        public T this[int index]
+        {
+            get
+            {
+                if (index < 0 || index >= Count)
+                    throw new ArgumentOutOfRangeException("index");
+
+                return _buffer[(_tail + index) % Capacity];
+            }
+            set
+            {
+                if (index < 0 || index >= Count)
+                    throw new ArgumentOutOfRangeException("index");
+
+                _buffer[(_tail + index) % Capacity] = value;
+            }
+        }
+
+        public int IndexOf(T item)
+        {
+            for (var i = 0; i < Count; ++i)
+                if (Equals(item, this[i]))
+                    return i;
+            return -1;
+        }
+
+        public void Insert(int index, T item)
+        {
+            if (index < 0 || index > Count)
+                throw new ArgumentOutOfRangeException("index");
+
+            if (Count == index)
+                Enqueue(item);
+            else
+            {
+                var last = this[Count - 1];
+                for (var i = index; i < Count - 2; ++i)
+                    this[i + 1] = this[i];
+                this[index] = item;
+                Enqueue(last);
+            }
+        }
+
+        public void RemoveAt(int index)
+        {
+            if (index < 0 || index >= Count)
+                throw new ArgumentOutOfRangeException("index");
+
+            for (var i = index; i > 0; --i)
+                this[i] = this[i - 1];
+            Dequeue();
+        }
+
+        public IEnumerator<T> GetEnumerator()
+        {
+            if (Count == 0 || Capacity == 0)
+                yield break;
+
+            for (var i = 0; i < Count; ++i)
+                yield return this[i];
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+    }
+}

+ 235 - 0
NTERA/Game/GameProc/Function/Clipboard.cs

@@ -0,0 +1,235 @@
+//using System;
+//using System.Text;
+//using System.Text.RegularExpressions;
+//using System.Timers;
+//using System.Windows.Forms;
+//using MinorShift.Emuera.GameView;
+//using Timer = System.Timers.Timer;
+
+//namespace MinorShift.Emuera.GameProc.Function
+//{
+//    internal class ClipboardProcessor
+//    {
+//        private readonly bool useCB;
+//        private readonly bool classicMode; // New Lines Only mode
+
+//        private readonly MainWindow mainWin;
+
+//        private bool minTimePassed; //Has enough time passed since the last Clipboard update?
+//        private bool postWaiting; //Is there text waiting to be sent to clipboard?
+//        private static Timer minTimer; //Minimum timer for refrehsing the clipboard to prevent spam
+
+//        private readonly int MaxCB; //Max length in lines of the output to clipboard
+//        private int ScrollPos; //Position of the clipboard output in the buffer
+//        private readonly int ScrollCount; //Lines to scroll at a time
+//        private int NewLineCount; //Number of new lines
+//        private int OldNewLineCount; //Number of lines in the last update, used for Classic mode + scrolling back to bottom
+//        private StringBuilder OldText; //Last set of lines sent to the clipboard
+//        private readonly CircularBuffer<string> lineBuffer; //Buffer for processed strings ready for clipboard
+
+//        public string GetLatestString => OldText.ToString();
+
+//        internal enum CBTriggers
+//        {
+//            LeftClick,
+//            MiddleClick,
+//            DoubleLeftClick,
+//            AnyKeyWait,
+//            InputWait
+//        }
+
+//        private delegate void SetClipboardDelegate(string text, bool copy, int times, int delay); //Just for using the timer to set the clipboard.
+
+//        public ClipboardProcessor(MainWindow parent)
+//        {
+//            useCB = Config.CBUseClipboard;
+//            classicMode = Config.CBNewLinesOnly;
+
+//            mainWin = parent;
+
+//            minTimePassed = true;
+//            postWaiting = false;
+
+//            MaxCB = Config.CBMaxCB;
+//            ScrollPos = 0; //FIXIT - Expand it, add a button, etc
+//            ScrollCount = Config.CBScrollCount; //FIXIT - Actually use it
+//            NewLineCount = 0;
+//            OldNewLineCount = 0;
+
+//            if (!useCB) return;
+
+//            lineBuffer = new CircularBuffer<string>(Config.CBBufferSize);
+//            minTimer = new Timer(Config.CBMinTimer) {AutoReset = false};
+//            minTimer.Elapsed += MinTimerDone;
+//            OldText = new StringBuilder();
+//        }
+
+//        public bool ScrollUp(int value)
+//        {
+//            if (!useCB) return false;
+//            if (ScrollPos == 0 && classicMode && ScrollCount > OldNewLineCount) ScrollPos = OldNewLineCount;
+//            else ScrollPos += ScrollCount * value;
+//            if (lineBuffer.Count < ScrollPos) ScrollPos = lineBuffer.Count - ScrollCount;
+//            SendToCB(true);
+//            return true;
+//        }
+
+//        public bool ScrollDown(int value)
+//        {
+//            if (!useCB) return false;
+//            ScrollPos -= ScrollCount;
+//            if (ScrollPos < 0) ScrollPos = 0;
+//            SendToCB(true);
+
+//            return true;
+//        }
+
+//        private void MinTimerDone(object source, ElapsedEventArgs e)
+//        {
+//            minTimePassed = true;
+//            if (postWaiting) SendToCB(true);
+//        }
+
+//        private bool MinTimeCheck()
+//        {
+//	        if (minTimePassed)
+//            {
+//                minTimePassed = false;
+//                minTimer.Start();
+//                return true;
+//            }
+
+//	        return false;
+//        }
+
+//        //FIXIT - Autoprocess old lines or just ditch?
+//        public void AddLine(ConsoleDisplayLine inputLine, bool left)
+//        {
+//            if (!useCB) return;
+
+//            NewLineCount++;
+//            string processed = ProcessLine(inputLine.ToString());
+//            lineBuffer.Enqueue(processed);
+//        }
+
+//        public void DelLine(int count)
+//        {
+//            if (!useCB || count <= 0) return;
+
+//            NewLineCount = Math.Max(0, NewLineCount - count);
+//            if (count >= lineBuffer.Count) lineBuffer.Clear();
+//            else
+//            {
+//                while (count > 0)
+//                {
+//                    lineBuffer.Dequeue();
+//                    count--;
+//                }
+//            }
+//        }
+
+//        public void ClearScreen()
+//        {
+//            if (!useCB) return;
+//            if (Config.CBClearBuffer)
+//            {
+//                lineBuffer.Clear();
+//                ScrollPos = 0;
+//                NewLineCount = 0;
+//            }
+//            else
+//            {
+//                lineBuffer.Enqueue("");
+//            }
+//        }
+
+//        public void Check(CBTriggers type)
+//        {
+//            if (!useCB) return;
+//            switch (type)
+//            {
+//                case CBTriggers.LeftClick:
+//                    if (!Config.CBTriggerLeftClick) return;
+//                    break;
+
+//                case CBTriggers.MiddleClick:
+//                    if (!Config.CBTriggerMiddleClick) return;
+//                    break;
+
+//                case CBTriggers.DoubleLeftClick:
+//                    if (!Config.CBTriggerDoubleLeftClick) return;
+//                    break;
+
+//                case CBTriggers.AnyKeyWait:
+//                    if (!Config.CBTriggerAnyKeyWait) return;
+//                    break;
+
+//                case CBTriggers.InputWait:
+//                    if (!Config.CBTriggerInputWait) return;
+//                    break;
+
+//                default:
+//                    return;
+//            }
+
+//            ScrollPos = 0;
+//            SendToCB(false);
+//        }
+
+//        private void SendToCB(bool force)
+//        {
+//            if (!useCB) return;
+//            if (NewLineCount == 0 && !force) return;
+//            if (!MinTimeCheck())
+//            {
+//                postWaiting = true;
+//                return;
+//            }
+
+//            if (NewLineCount == 0 && ScrollPos == 0) NewLineCount = OldNewLineCount;
+
+//            int length;
+//            if (classicMode && ScrollPos == 0) length = Math.Min(NewLineCount, lineBuffer.Count);
+//            else length = Math.Min(MaxCB, lineBuffer.Count - ScrollPos);
+//            if (length <= 0) return;
+
+//            var newText = new StringBuilder();
+//            for (int count = 0; count < length; count++)
+//            {
+//                newText.AppendLine(lineBuffer[lineBuffer.Count - length - ScrollPos + count]);
+//            }
+//            if (newText.ToString().Equals(OldText.ToString())) return;
+//            var scpDelegate = new SetClipboardDelegate(Clipboard.SetDataObject);
+//            try
+//            {
+//                mainWin.Invoke(scpDelegate, newText.ToString(), false, 3, 200);
+//                if (ScrollPos == 0) OldNewLineCount = NewLineCount;
+//                NewLineCount = 0;
+//                OldText = newText;
+//                postWaiting = false;
+//            }
+//            catch (Exception)
+//            {
+//                //FIXIT - For now it just fails silently
+//            }
+//        }
+
+//        private const string HTML_TAG_PATTERN = "<.*?>";
+
+//        public static string StripHTML(string input)
+//        {
+//            // still faster to use String.Contains to check if we need to do this at all first, supposedly
+//            if (Config.CBIgnoreTags && input.Contains("<"))
+//            {
+//                // regex is faster and simpler than a for loop you nerds
+//                return Regex.Replace(input, HTML_TAG_PATTERN, Config.CBReplaceTags);
+//            }
+//            return input;
+//        }
+
+//        private static string ProcessLine(string input)
+//        {
+//            return StripHTML(input);
+//        }
+//    }
+//}

+ 79 - 0
NTERA/Game/GameProc/Function/FunctionArgType.cs

@@ -0,0 +1,79 @@
+
+using System.Reflection;
+
+namespace MinorShift.Emuera.GameProc.Function
+{
+	/// <summary>
+	/// 命令の引数タイプ
+	/// </summary>
+	//難読化用属性。enum.ToString()やenum.Parse()を行うなら(Exclude=true)にすること。
+	[Obfuscation(Exclude=false)]
+	internal enum FunctionArgType
+	{//数値不要
+		__NULL__ = 0x0000,//未設定。エラー。引数がないならばVOIDを指定すること。
+		METHOD,//式中関数。
+
+		VOID,//引数なし
+		INT_EXPRESSION,//数式型。省略可能
+		INT_EXPRESSION_NULLABLE,//数式型
+		STR_EXPRESSION,//文字列式型
+        STR_EXPRESSION_NULLABLE,
+		STR,//単純文字列型
+		KEYWORD,//単純文字列型。特定の文字のみ有効
+		STR_NULLABLE,//単純文字列型、省略可能
+		FORM_STR,//書式付文字列型。
+		FORM_STR_NULLABLE,//書式付文字列型。省略可能
+		SP_PRINTV,//複数数式型。'~~,文字列可
+		SP_TIMES,//<数値型変数>,<実数定数>
+		SP_BAR,//<数値>,<数値>,<数値>
+		SP_SET,//可変数値変数・数式型。
+		SP_SETS,//可変文字列変数・単純又は複合文字列型。
+		SP_SWAP,//<数値>,<数値>
+		SP_VAR,//<変数>
+		SP_SAVEDATA,//<数値>,<文字列式>
+        SP_INPUT,//(<数値>) //引数はオプションでないのがデフォ、INT_EXPRESSION_NULLABLEとは処理が違う
+        SP_INPUTS,//(<FORM文字列>) //引数はオプションでないのがデフォ、STR_EXPRESSION_NULLABLEとは処理が違う
+        SP_ONEINPUT,//(<数値>, <数値>) //引数はオプションでないのがデフォ、第2引数はマウス入力時の2桁以上の値時の処理指定
+        SP_ONEINPUTS,//(<FORM文字列>, <数値>) //引数はオプションでないのがデフォ、第2引数はマウス入力時の2文字以上の文字列時の処理指定
+        SP_TINPUT,//<数値>,<数値>(,<数値>,<文字列>)
+        SP_TINPUTS,//<数値>,<文字列式>(,<数値>,<文字列>)
+		SP_SORTCHARA,//<キャラクタ変数>,<ソート順序>(両方省略可能)
+		SP_CALL,//<文字列>,<引数>,... //引数は省略可能
+		SP_CALLF,
+		SP_CALLFORM,//<書式付文字列>,<引数>,... //引数は省略可能
+		SP_CALLFORMF,//<書式付文字列>,<引数>,... //引数は省略可能
+		SP_FOR_NEXT,//<可変数値変数>,<数値>,<数値>,<数値> //引数は省略可能
+		SP_POWER,//<可変数値変数>,<数値>,<数値>
+		SP_SWAPVAR,//<可変変数>,<可変変数>(同型のみ)
+		EXPRESSION,//<式>、変数の型は不問
+		EXPRESSION_NULLABLE,//<式>、変数の型は不問
+		CASE,//<CASE条件式>(, <CASE条件式>...)
+		
+
+        //TODO 省略時の処理に違いがあるが統合可能なはず
+		VAR_INT,//<可変数値変数> //引数は省略可
+        SP_GETINT,//<可変数値変数>(今までこれがないことに驚いた)
+
+		VAR_STR,//<可変数値変数> //引数は省略可
+		BIT_ARG,//<可変数値変数>,<数値>*n (SP_SETが使えないため新設)
+		SP_VAR_SET,//<可変変数>,<数式 or 文字列式 or null>(,<範囲初値>, <範囲終値>)
+		SP_BUTTON,//<文字列式>,<数式>
+		SP_SET_ARRAY,//可変数値変数・<数式配列型>。未使用
+		SP_SETS_ARRAY,//可変文字列変数・<文字列配列型>。未使用
+		SP_COLOR,
+		SP_SPLIT,//<文字列式>, <文字列式>, <可変文字変数>
+		SP_CVAR_SET,//<可変変数>,<式>,<数式 or 文字列式 or null>(,<範囲初値>, <範囲終値>)
+		SP_CONTROL_ARRAY,//<可変変数>,<数値>,<数値>
+		SP_SHIFT_ARRAY,//<可変変数>,<数値>,<数値or文字列>(,<数値>,<数値>)
+        SP_SORTARRAY,//<対象変数>, (<ソート順序>, <範囲初値>, <範囲終値>)
+        INT_ANY,//1つ以上の数値を任意数
+		FORM_STR_ANY,//1つ以上のFORM文字列を任意数  
+		SP_COPYCHARA,//<数値>(, <数値)第二引数省略可
+		SP_COPY_ARRAY,//<文字列式>,<文字列式>
+		SP_SAVEVAR,//<数値>,<文字列式>, <変数>(, <変数>...)
+		SP_SAVECHARA,//<数値>, <文字列式>, <数値>(, <数値>...)第二引数省略可
+		SP_REF,
+		SP_REFBYNAME,
+		SP_HTMLSPLIT
+	}
+}

+ 575 - 0
NTERA/Game/GameProc/Function/FunctionIdentifier.cs

@@ -0,0 +1,575 @@
+using System.Collections.Generic;
+using MinorShift.Emuera.GameData.Function;
+
+namespace MinorShift.Emuera.GameProc.Function
+{
+	/// <summary>
+	/// FunctionCodeのラッパー
+	/// BuiltInFunctionManagerを元にクラス化
+	/// </summary>
+	internal sealed partial class FunctionIdentifier
+	{
+		#region flag定義
+		//いちいちFunctionFlag.FLOW_CONTROLとか書くのが面倒だったからenumではなくconst intで
+	    private const int FLOW_CONTROL = 0x00001;
+        private const int EXTENDED = 0x00002;//Emuera拡張命令
+		private const int METHOD_SAFE = 0x00004;//#Function中で呼び出してよい命令。WAITなど入力を伴うもの、CALLなど関数呼び出しを伴うものは不可。
+		private const int DEBUG_FUNC = 0x00008;//-Debug引数付きで起動した場合にのみ実行される命令。
+		private const int PARTIAL = 0x00010;//複数行に渡る構文の一部である命令。SIF文の次に来てはいけない。debugコマンドからの呼び出しも不適当。
+		private const int FORCE_SETARG = 0x00020;//ロード時に必ず引数解析を行う必要のあるもの。IFやSELECTCASEなど
+		private const int IS_JUMP = 0x00040;//JUMP命令
+		private const int IS_TRY = 0x00080;//TRY系命令
+		private const int IS_TRYC = 0x08000;//TRY系命令
+
+		private const int PRINT_NEWLINE = 0x00100;//PRINT命令で出力後改行するもの
+		private const int PRINT_WAITINPUT = 0x00200;//PRINT命令で出力後入力待ちするもの
+		private const int PRINT_SINGLE = 0x00400;//PRINTSINGLE系
+		private const int ISPRINTDFUNC = 0x00800;//PRINTD系判定用
+		private const int ISPRINTKFUNC = 0x01000;//PRINTK系判定用
+
+		private const int IS_PRINT = 0x02000;//SkipPrintにより飛ばされる命令。PRINT系及びWAIT系。DEBUGPRINTは含まない。
+		private const int IS_INPUT = 0x04000;//userDefinedSkipを警告する命令。INPUT系。
+		private const int IS_PRINTDATA = 0x10000;//PRINTDATA系判定用、PRINTとは一部処理が違うので、それ用。
+
+		#endregion
+
+		#region static
+		//元BuiltInFunctionManager部分
+	    private static readonly Dictionary<string, FunctionIdentifier> funcDic = new Dictionary<string, FunctionIdentifier>();
+		static readonly Dictionary<FunctionCode, string> funcMatch = new Dictionary<FunctionCode, string>();
+		static readonly Dictionary<FunctionCode, FunctionCode> funcParent = new Dictionary<FunctionCode, FunctionCode>();
+		static readonly AbstractInstruction methodInstruction;
+
+	    private static void AddFunction(FunctionCode code, AbstractInstruction inst, int additionalFlag = 0)
+		{
+			var key = code.ToString();
+			if (Config.ICFunction)
+				key = key.ToUpper();
+			funcDic.Add(key, new FunctionIdentifier(key, code, inst, additionalFlag));
+		}
+
+		private static void AddFunction(FunctionCode code, ArgumentBuilder arg)
+		{ AddFunction(code, arg, 0); }
+
+		private static void AddFunction(FunctionCode code, ArgumentBuilder arg, int flag)
+		{
+			var key = code.ToString();
+			if (Config.ICFunction)
+				key = key.ToUpper();
+			funcDic.Add(key, new FunctionIdentifier(key, code, arg, flag));
+		}
+
+		public static Dictionary<string, FunctionIdentifier> GetInstructionNameDic()
+		{
+			return funcDic;
+		}
+		private static void addPrintFunction(FunctionCode code)
+		{
+			AddFunction(code, new PRINT_Instruction(code.ToString()));
+		}
+		private static void addPrintDataFunction(FunctionCode code)
+		{
+			AddFunction(code, new PRINT_DATA_Instruction(code.ToString()));
+		}
+		static FunctionIdentifier()
+		{
+			var argb = ArgumentParser.GetArgumentBuilderDictionary();
+			methodInstruction = new METHOD_Instruction();
+			SETFunction = new FunctionIdentifier("SET", FunctionCode.SET, new SET_Instruction());//代入文
+			#region PRINT or INPUT
+			addPrintFunction(FunctionCode.PRINT);
+			addPrintFunction(FunctionCode.PRINTL);
+			addPrintFunction(FunctionCode.PRINTW);
+			addPrintFunction(FunctionCode.PRINTV);
+			addPrintFunction(FunctionCode.PRINTVL);
+			addPrintFunction(FunctionCode.PRINTVW);
+			addPrintFunction(FunctionCode.PRINTS);
+			addPrintFunction(FunctionCode.PRINTSL);
+			addPrintFunction(FunctionCode.PRINTSW);
+			addPrintFunction(FunctionCode.PRINTFORM);
+			addPrintFunction(FunctionCode.PRINTFORML);
+			addPrintFunction(FunctionCode.PRINTFORMW);
+			addPrintFunction(FunctionCode.PRINTFORMS);
+			addPrintFunction(FunctionCode.PRINTFORMSL);
+			addPrintFunction(FunctionCode.PRINTFORMSW);
+			addPrintFunction(FunctionCode.PRINTK);
+			addPrintFunction(FunctionCode.PRINTKL);
+			addPrintFunction(FunctionCode.PRINTKW);
+			addPrintFunction(FunctionCode.PRINTVK);
+			addPrintFunction(FunctionCode.PRINTVKL);
+			addPrintFunction(FunctionCode.PRINTVKW);
+			addPrintFunction(FunctionCode.PRINTSK);
+			addPrintFunction(FunctionCode.PRINTSKL);
+			addPrintFunction(FunctionCode.PRINTSKW);
+			addPrintFunction(FunctionCode.PRINTFORMK);
+			addPrintFunction(FunctionCode.PRINTFORMKL);
+			addPrintFunction(FunctionCode.PRINTFORMKW);
+			addPrintFunction(FunctionCode.PRINTFORMSK);
+			addPrintFunction(FunctionCode.PRINTFORMSKL);
+			addPrintFunction(FunctionCode.PRINTFORMSKW);
+			addPrintFunction(FunctionCode.PRINTD);
+			addPrintFunction(FunctionCode.PRINTDL);
+			addPrintFunction(FunctionCode.PRINTDW);
+			addPrintFunction(FunctionCode.PRINTVD);
+			addPrintFunction(FunctionCode.PRINTVDL);
+			addPrintFunction(FunctionCode.PRINTVDW);
+			addPrintFunction(FunctionCode.PRINTSD);
+			addPrintFunction(FunctionCode.PRINTSDL);
+			addPrintFunction(FunctionCode.PRINTSDW);
+			addPrintFunction(FunctionCode.PRINTFORMD);
+			addPrintFunction(FunctionCode.PRINTFORMDL);
+			addPrintFunction(FunctionCode.PRINTFORMDW);
+			addPrintFunction(FunctionCode.PRINTFORMSD);
+			addPrintFunction(FunctionCode.PRINTFORMSDL);
+			addPrintFunction(FunctionCode.PRINTFORMSDW);
+			addPrintFunction(FunctionCode.PRINTSINGLE);
+			addPrintFunction(FunctionCode.PRINTSINGLEV);
+			addPrintFunction(FunctionCode.PRINTSINGLES);
+			addPrintFunction(FunctionCode.PRINTSINGLEFORM);
+			addPrintFunction(FunctionCode.PRINTSINGLEFORMS);
+			addPrintFunction(FunctionCode.PRINTSINGLEK);
+			addPrintFunction(FunctionCode.PRINTSINGLEVK);
+			addPrintFunction(FunctionCode.PRINTSINGLESK);
+			addPrintFunction(FunctionCode.PRINTSINGLEFORMK);
+			addPrintFunction(FunctionCode.PRINTSINGLEFORMSK);
+			addPrintFunction(FunctionCode.PRINTSINGLED);
+			addPrintFunction(FunctionCode.PRINTSINGLEVD);
+			addPrintFunction(FunctionCode.PRINTSINGLESD);
+			addPrintFunction(FunctionCode.PRINTSINGLEFORMD);
+			addPrintFunction(FunctionCode.PRINTSINGLEFORMSD);
+
+			addPrintFunction(FunctionCode.PRINTC);
+			addPrintFunction(FunctionCode.PRINTLC);
+			addPrintFunction(FunctionCode.PRINTFORMC);
+			addPrintFunction(FunctionCode.PRINTFORMLC);
+			addPrintFunction(FunctionCode.PRINTCK);
+			addPrintFunction(FunctionCode.PRINTLCK);
+			addPrintFunction(FunctionCode.PRINTFORMCK);
+			addPrintFunction(FunctionCode.PRINTFORMLCK);
+			addPrintFunction(FunctionCode.PRINTCD);
+			addPrintFunction(FunctionCode.PRINTLCD);
+			addPrintFunction(FunctionCode.PRINTFORMCD);
+			addPrintFunction(FunctionCode.PRINTFORMLCD);
+			addPrintDataFunction(FunctionCode.PRINTDATA);
+			addPrintDataFunction(FunctionCode.PRINTDATAL);
+			addPrintDataFunction(FunctionCode.PRINTDATAW);
+			addPrintDataFunction(FunctionCode.PRINTDATAK);
+			addPrintDataFunction(FunctionCode.PRINTDATAKL);
+			addPrintDataFunction(FunctionCode.PRINTDATAKW);
+			addPrintDataFunction(FunctionCode.PRINTDATAD);
+			addPrintDataFunction(FunctionCode.PRINTDATADL);
+			addPrintDataFunction(FunctionCode.PRINTDATADW);
+
+
+			AddFunction(FunctionCode.PRINTBUTTON, argb[FunctionArgType.SP_BUTTON], METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.PRINTBUTTONC, argb[FunctionArgType.SP_BUTTON], METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.PRINTBUTTONLC, argb[FunctionArgType.SP_BUTTON], METHOD_SAFE | EXTENDED);
+
+			AddFunction(FunctionCode.PRINTPLAIN, argb[FunctionArgType.STR_NULLABLE], METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.PRINTPLAINFORM, argb[FunctionArgType.FORM_STR_NULLABLE], METHOD_SAFE | EXTENDED);
+
+			AddFunction(FunctionCode.PRINT_ABL, argb[FunctionArgType.INT_EXPRESSION], METHOD_SAFE);//能力。引数は登録番号
+			AddFunction(FunctionCode.PRINT_TALENT, argb[FunctionArgType.INT_EXPRESSION], METHOD_SAFE);//素質
+			AddFunction(FunctionCode.PRINT_MARK, argb[FunctionArgType.INT_EXPRESSION], METHOD_SAFE);//刻印
+			AddFunction(FunctionCode.PRINT_EXP, argb[FunctionArgType.INT_EXPRESSION], METHOD_SAFE);//経験
+			AddFunction(FunctionCode.PRINT_PALAM, argb[FunctionArgType.INT_EXPRESSION], METHOD_SAFE);//パラメータ
+			AddFunction(FunctionCode.PRINT_ITEM, argb[FunctionArgType.VOID], METHOD_SAFE);//所持アイテム
+			AddFunction(FunctionCode.PRINT_SHOPITEM, argb[FunctionArgType.VOID], METHOD_SAFE);//ショップで売っているアイテム
+
+			AddFunction(FunctionCode.DRAWLINE, argb[FunctionArgType.VOID], METHOD_SAFE);//画面の左端から右端まで----と線を引く。
+			AddFunction(FunctionCode.BAR, new BAR_Instruction(false));//[*****....]のようなグラフを書く。BAR (変数) , (最大値), (長さ)
+			AddFunction(FunctionCode.BARL, new BAR_Instruction(true));//改行付き。
+			AddFunction(FunctionCode.TIMES, new TIMES_Instruction());//小数計算。TIMES (変数) , (小数値)という形で使う。
+
+			AddFunction(FunctionCode.WAIT, new WAIT_Instruction(false));
+			AddFunction(FunctionCode.INPUT, new INPUT_Instruction());
+			AddFunction(FunctionCode.INPUTS, new INPUTS_Instruction());
+			AddFunction(FunctionCode.TINPUT, new TINPUT_Instruction(false));
+			AddFunction(FunctionCode.TINPUTS, new TINPUTS_Instruction(false));
+			AddFunction(FunctionCode.TONEINPUT, new TINPUT_Instruction(true));
+			AddFunction(FunctionCode.TONEINPUTS, new TINPUTS_Instruction(true));
+			AddFunction(FunctionCode.TWAIT, new TWAIT_Instruction());
+			AddFunction(FunctionCode.WAITANYKEY, new WAITANYKEY_Instruction());
+			AddFunction(FunctionCode.FORCEWAIT, new WAIT_Instruction(true));
+			AddFunction(FunctionCode.ONEINPUT, new ONEINPUT_Instruction());
+			AddFunction(FunctionCode.ONEINPUTS, new ONEINPUTS_Instruction());
+			AddFunction(FunctionCode.CLEARLINE, new CLEARLINE_Instruction());
+			AddFunction(FunctionCode.REUSELASTLINE, new REUSELASTLINE_Instruction());
+
+			#endregion
+			AddFunction(FunctionCode.UPCHECK, argb[FunctionArgType.VOID], METHOD_SAFE);//パラメータの変動
+			AddFunction(FunctionCode.CUPCHECK, argb[FunctionArgType.INT_EXPRESSION], METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.ADDCHARA, new ADDCHARA_Instruction(false, false));//(キャラ番号)のキャラクタを追加
+			AddFunction(FunctionCode.ADDSPCHARA, new ADDCHARA_Instruction(true, false));//(キャラ番号)のSPキャラクタを追加(フラグ0を1にして作成)
+			AddFunction(FunctionCode.ADDDEFCHARA, argb[FunctionArgType.VOID], METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.ADDVOIDCHARA, new ADDVOIDCHARA_Instruction());//変数に何の設定のないキャラを作成
+			AddFunction(FunctionCode.DELCHARA, new ADDCHARA_Instruction(false, true));//(キャラ登録番号)のキャラクタを削除。
+
+			AddFunction(FunctionCode.PUTFORM, argb[FunctionArgType.FORM_STR_NULLABLE], METHOD_SAFE);//@SAVEINFO関数でのみ使用可能。PRINTFORMと同様の書式でセーブデータに概要をつける。
+			AddFunction(FunctionCode.QUIT, argb[FunctionArgType.VOID]);//ゲームを終了
+			AddFunction(FunctionCode.OUTPUTLOG, argb[FunctionArgType.VOID]);
+
+			AddFunction(FunctionCode.BEGIN, new BEGIN_Instruction());//システム関数の実行。実行するとCALLの呼び出し元などを忘れてしまう。
+
+			AddFunction(FunctionCode.SAVEGAME, new SAVELOADGAME_Instruction(true));//セーブ画面を呼ぶ。ショップのみ。
+			AddFunction(FunctionCode.LOADGAME, new SAVELOADGAME_Instruction(false));//
+			AddFunction(FunctionCode.SAVEDATA, argb[FunctionArgType.SP_SAVEDATA], METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.LOADDATA, argb[FunctionArgType.INT_EXPRESSION], EXTENDED | FLOW_CONTROL);
+			AddFunction(FunctionCode.DELDATA, new DELDATA_Instruction());
+			AddFunction(FunctionCode.SAVEGLOBAL, new SAVEGLOBAL_Instruction());
+			AddFunction(FunctionCode.LOADGLOBAL, new LOADGLOBAL_Instruction());
+			AddFunction(FunctionCode.RESETDATA, new RESETDATA_Instruction());
+			AddFunction(FunctionCode.RESETGLOBAL, new RESETGLOBAL_Instruction());
+
+			AddFunction(FunctionCode.SIF, new SIF_Instruction());//一行のみIF
+			AddFunction(FunctionCode.IF, new IF_Instruction());
+			AddFunction(FunctionCode.ELSE, new ELSEIF_Instruction(FunctionArgType.VOID));
+			AddFunction(FunctionCode.ELSEIF, new ELSEIF_Instruction(FunctionArgType.INT_EXPRESSION));
+			AddFunction(FunctionCode.ENDIF, new ENDIF_Instruction(), METHOD_SAFE);
+			AddFunction(FunctionCode.SELECTCASE, new SELECTCASE_Instruction());
+			AddFunction(FunctionCode.CASE, new ELSEIF_Instruction(FunctionArgType.CASE), EXTENDED);
+			AddFunction(FunctionCode.CASEELSE, new ELSEIF_Instruction(FunctionArgType.VOID), EXTENDED);
+			AddFunction(FunctionCode.ENDSELECT, new ENDIF_Instruction(), METHOD_SAFE | EXTENDED);
+
+			AddFunction(FunctionCode.REPEAT, new REPEAT_Instruction(false));//RENDまで繰り返し。繰り返した回数がCOUNTへ。ネスト不可。
+			AddFunction(FunctionCode.REND, new REND_Instruction());
+			AddFunction(FunctionCode.FOR, new REPEAT_Instruction(true), EXTENDED);
+			AddFunction(FunctionCode.NEXT, new REND_Instruction(), EXTENDED);
+			AddFunction(FunctionCode.WHILE, new WHILE_Instruction());
+			AddFunction(FunctionCode.WEND, new WEND_Instruction());
+			AddFunction(FunctionCode.DO, new ENDIF_Instruction(), METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.LOOP, new LOOP_Instruction());
+			AddFunction(FunctionCode.CONTINUE, new CONTINUE_Instruction());//REPEATに戻る
+			AddFunction(FunctionCode.BREAK, new BREAK_Instruction());//RENDの次の行まで
+
+			AddFunction(FunctionCode.RETURN, new RETURN_Instruction());//関数の終了。RESULTに整数を格納可能。省略した場合、0。(次の@~~がRETURNと見なされる。)  
+			AddFunction(FunctionCode.RETURNFORM, new RETURNFORM_Instruction());//関数の終了。RESULTに整数を格納可能。省略した場合、0。(次の@~~がRETURNと見なされる。)  
+			AddFunction(FunctionCode.RETURNF, new RETURNF_Instruction());
+
+			AddFunction(FunctionCode.STRLEN, new STRLEN_Instruction(false, false));
+			AddFunction(FunctionCode.STRLENFORM, new STRLEN_Instruction(true, false));
+			AddFunction(FunctionCode.STRLENU, new STRLEN_Instruction(false, true));
+			AddFunction(FunctionCode.STRLENFORMU, new STRLEN_Instruction(true, true));
+
+			AddFunction(FunctionCode.SWAPCHARA, new SWAPCHARA_Instruction());
+			AddFunction(FunctionCode.COPYCHARA, new COPYCHARA_Instruction());
+			AddFunction(FunctionCode.ADDCOPYCHARA, new ADDCOPYCHARA_Instruction());
+			AddFunction(FunctionCode.SPLIT, argb[FunctionArgType.SP_SPLIT], METHOD_SAFE | EXTENDED);
+
+			AddFunction(FunctionCode.SETCOLOR, argb[FunctionArgType.SP_COLOR], METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.SETCOLORBYNAME, argb[FunctionArgType.STR], METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.RESETCOLOR, new RESETCOLOR_Instruction());
+			AddFunction(FunctionCode.SETBGCOLOR, argb[FunctionArgType.SP_COLOR], METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.SETBGCOLORBYNAME, argb[FunctionArgType.STR], METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.RESETBGCOLOR, new RESETBGCOLOR_Instruction());
+			AddFunction(FunctionCode.FONTBOLD, new FONTBOLD_Instruction());
+			AddFunction(FunctionCode.FONTITALIC, new FONTITALIC_Instruction());
+			AddFunction(FunctionCode.FONTREGULAR, new FONTREGULAR_Instruction());
+			AddFunction(FunctionCode.SORTCHARA, new SORTCHARA_Instruction());
+			AddFunction(FunctionCode.FONTSTYLE, argb[FunctionArgType.INT_EXPRESSION_NULLABLE], METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.ALIGNMENT, argb[FunctionArgType.STR], METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.CUSTOMDRAWLINE, argb[FunctionArgType.STR], METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.DRAWLINEFORM, argb[FunctionArgType.FORM_STR], METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.CLEARTEXTBOX, argb[FunctionArgType.VOID], METHOD_SAFE | EXTENDED);
+
+			AddFunction(FunctionCode.SETFONT, argb[FunctionArgType.STR_EXPRESSION_NULLABLE], METHOD_SAFE | EXTENDED);
+
+			AddFunction(FunctionCode.SWAP, argb[FunctionArgType.SP_SWAPVAR], METHOD_SAFE | EXTENDED);
+
+			AddFunction(FunctionCode.RANDOMIZE, new RANDOMIZE_Instruction());
+			AddFunction(FunctionCode.DUMPRAND, new DUMPRAND_Instruction());
+			AddFunction(FunctionCode.INITRAND, new INITRAND_Instruction());
+
+			AddFunction(FunctionCode.REDRAW, argb[FunctionArgType.INT_EXPRESSION], METHOD_SAFE | EXTENDED);
+
+			AddFunction(FunctionCode.CALLTRAIN, argb[FunctionArgType.INT_EXPRESSION], EXTENDED | FLOW_CONTROL);
+			AddFunction(FunctionCode.STOPCALLTRAIN, argb[FunctionArgType.VOID], EXTENDED | FLOW_CONTROL);
+			AddFunction(FunctionCode.DOTRAIN, argb[FunctionArgType.INT_EXPRESSION], EXTENDED | FLOW_CONTROL);
+
+			AddFunction(FunctionCode.DATA, argb[FunctionArgType.STR_NULLABLE], METHOD_SAFE | EXTENDED | PARTIAL | PARTIAL);
+			AddFunction(FunctionCode.DATAFORM, argb[FunctionArgType.FORM_STR_NULLABLE], METHOD_SAFE | EXTENDED | PARTIAL);
+			AddFunction(FunctionCode.ENDDATA, new DO_NOTHING_Instruction());
+			AddFunction(FunctionCode.DATALIST, argb[FunctionArgType.VOID], METHOD_SAFE | EXTENDED | PARTIAL);
+			AddFunction(FunctionCode.ENDLIST, argb[FunctionArgType.VOID], METHOD_SAFE | EXTENDED | PARTIAL);
+			AddFunction(FunctionCode.STRDATA, argb[FunctionArgType.VAR_STR], METHOD_SAFE | EXTENDED | PARTIAL);
+
+			AddFunction(FunctionCode.SETBIT, new SETBIT_Instruction(1));
+			AddFunction(FunctionCode.CLEARBIT, new SETBIT_Instruction(0));
+			AddFunction(FunctionCode.INVERTBIT, new SETBIT_Instruction(-1));
+			AddFunction(FunctionCode.DELALLCHARA, argb[FunctionArgType.VOID], METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.PICKUPCHARA, argb[FunctionArgType.INT_ANY], METHOD_SAFE | EXTENDED);
+
+			AddFunction(FunctionCode.VARSET, new VARSET_Instruction());
+			AddFunction(FunctionCode.CVARSET, new CVARSET_Instruction());
+
+			AddFunction(FunctionCode.RESET_STAIN, argb[FunctionArgType.INT_EXPRESSION], METHOD_SAFE | EXTENDED);
+
+			AddFunction(FunctionCode.FORCEKANA, argb[FunctionArgType.INT_EXPRESSION], METHOD_SAFE | EXTENDED);
+
+			AddFunction(FunctionCode.SKIPDISP, argb[FunctionArgType.INT_EXPRESSION], METHOD_SAFE | EXTENDED);
+
+			AddFunction(FunctionCode.NOSKIP, argb[FunctionArgType.VOID], METHOD_SAFE | EXTENDED | PARTIAL);
+			AddFunction(FunctionCode.ENDNOSKIP, argb[FunctionArgType.VOID], METHOD_SAFE | EXTENDED | PARTIAL);
+
+			AddFunction(FunctionCode.ARRAYSHIFT, argb[FunctionArgType.SP_SHIFT_ARRAY], METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.ARRAYREMOVE, argb[FunctionArgType.SP_CONTROL_ARRAY], METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.ARRAYSORT, argb[FunctionArgType.SP_SORTARRAY], METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.ARRAYCOPY, argb[FunctionArgType.SP_COPY_ARRAY], METHOD_SAFE | EXTENDED);
+
+			AddFunction(FunctionCode.JUMP, new CALL_Instruction(false, true, false, false));//関数に移動
+			AddFunction(FunctionCode.CALL, new CALL_Instruction(false, false, false, false));//関数に移動。移動元を記憶し、RETURNで帰る。
+			AddFunction(FunctionCode.TRYJUMP, new CALL_Instruction(false, true, true, false), EXTENDED);
+			AddFunction(FunctionCode.TRYCALL, new CALL_Instruction(false, false, true, false), EXTENDED);
+			AddFunction(FunctionCode.JUMPFORM, new CALL_Instruction(true, true, false, false), EXTENDED);
+			AddFunction(FunctionCode.CALLFORM, new CALL_Instruction(true, false, false, false), EXTENDED);
+			AddFunction(FunctionCode.TRYJUMPFORM, new CALL_Instruction(true, true, true, false), EXTENDED);
+			AddFunction(FunctionCode.TRYCALLFORM, new CALL_Instruction(true, false, true, false), EXTENDED);
+			AddFunction(FunctionCode.TRYCJUMP, new CALL_Instruction(false, true, true, true), EXTENDED);
+			AddFunction(FunctionCode.TRYCCALL, new CALL_Instruction(false, false, true, true), EXTENDED);
+			AddFunction(FunctionCode.TRYCJUMPFORM, new CALL_Instruction(true, true, true, true), EXTENDED);
+			AddFunction(FunctionCode.TRYCCALLFORM, new CALL_Instruction(true, false, true, true), EXTENDED);
+			AddFunction(FunctionCode.CALLEVENT, new CALLEVENT_Instruction());
+			AddFunction(FunctionCode.CALLF, new CALLF_Instruction(false));
+			AddFunction(FunctionCode.CALLFORMF, new CALLF_Instruction(true));
+			AddFunction(FunctionCode.RESTART, new RESTART_Instruction());//関数の再開。関数の最初に戻る。
+			AddFunction(FunctionCode.GOTO, new GOTO_Instruction(false, false, false));//$ラベルへジャンプ
+			AddFunction(FunctionCode.TRYGOTO, new GOTO_Instruction(false, true, false), EXTENDED);
+			AddFunction(FunctionCode.GOTOFORM, new GOTO_Instruction(true, false, false), EXTENDED);
+			AddFunction(FunctionCode.TRYGOTOFORM, new GOTO_Instruction(true, true, false), EXTENDED);
+			AddFunction(FunctionCode.TRYCGOTO, new GOTO_Instruction(false, true, true), EXTENDED);
+			AddFunction(FunctionCode.TRYCGOTOFORM, new GOTO_Instruction(true, true, true), EXTENDED);
+
+
+			AddFunction(FunctionCode.CATCH, new CATCH_Instruction());
+			AddFunction(FunctionCode.ENDCATCH, new ENDIF_Instruction(), METHOD_SAFE | EXTENDED);
+			AddFunction(FunctionCode.TRYCALLLIST, argb[FunctionArgType.VOID], EXTENDED | FLOW_CONTROL | PARTIAL | IS_TRY);
+			AddFunction(FunctionCode.TRYJUMPLIST, argb[FunctionArgType.VOID], EXTENDED | FLOW_CONTROL | PARTIAL | IS_JUMP | IS_TRY);
+			AddFunction(FunctionCode.TRYGOTOLIST, argb[FunctionArgType.VOID], EXTENDED | FLOW_CONTROL | PARTIAL | IS_TRY);
+			AddFunction(FunctionCode.FUNC, argb[FunctionArgType.SP_CALLFORM], EXTENDED | FLOW_CONTROL | PARTIAL | FORCE_SETARG);
+			AddFunction(FunctionCode.ENDFUNC, new ENDIF_Instruction(), EXTENDED);
+
+			AddFunction(FunctionCode.DEBUGPRINT, new DEBUGPRINT_Instruction(false, false));
+			AddFunction(FunctionCode.DEBUGPRINTL, new DEBUGPRINT_Instruction(false, true));
+			AddFunction(FunctionCode.DEBUGPRINTFORM, new DEBUGPRINT_Instruction(true, false));
+			AddFunction(FunctionCode.DEBUGPRINTFORML, new DEBUGPRINT_Instruction(true, true));
+			AddFunction(FunctionCode.DEBUGCLEAR, new DEBUGCLEAR_Instruction());
+			AddFunction(FunctionCode.ASSERT, argb[FunctionArgType.INT_EXPRESSION], METHOD_SAFE | EXTENDED | DEBUG_FUNC);
+			AddFunction(FunctionCode.THROW, argb[FunctionArgType.FORM_STR_NULLABLE], METHOD_SAFE | EXTENDED);
+
+			AddFunction(FunctionCode.SAVEVAR, new SAVEVAR_Instruction());
+			AddFunction(FunctionCode.LOADVAR, new LOADVAR_Instruction());
+			AddFunction(FunctionCode.SAVECHARA, new SAVECHARA_Instruction());
+			AddFunction(FunctionCode.LOADCHARA, new LOADCHARA_Instruction());
+			AddFunction(FunctionCode.REF, new REF_Instruction(false));
+			AddFunction(FunctionCode.REFBYNAME, new REF_Instruction(true));
+			AddFunction(FunctionCode.HTML_PRINT, new HTML_PRINT_Instruction());
+            AddFunction(FunctionCode.HTML_PRINTSL, new HTML_PRINT_Instruction(true));
+            AddFunction(FunctionCode.HTML_TAGSPLIT, new HTML_TAGSPLIT_Instruction());
+			AddFunction(FunctionCode.PRINT_IMG, new PRINT_IMG_Instruction());
+			AddFunction(FunctionCode.PRINT_RECT, new PRINT_RECT_Instruction());
+			AddFunction(FunctionCode.PRINT_SPACE, new PRINT_SPACE_Instruction());
+			
+			AddFunction(FunctionCode.TOOLTIP_SETCOLOR, new TOOLTIP_SETCOLOR_Instruction());
+			AddFunction(FunctionCode.TOOLTIP_SETDELAY, new TOOLTIP_SETDELAY_Instruction());
+	                AddFunction(FunctionCode.TOOLTIP_SETDURATION, new TOOLTIP_SETDURATION_Instruction());
+
+			#region 式中関数の引数違い
+			AddFunction(FunctionCode.VARSIZE, argb[FunctionArgType.SP_VAR], METHOD_SAFE | EXTENDED);//動作が違うのでMETHOD化できない
+			AddFunction(FunctionCode.GETTIME, argb[FunctionArgType.VOID], METHOD_SAFE | EXTENDED);//2つに代入する必要があるのでMETHOD化できない
+			AddFunction(FunctionCode.POWER, argb[FunctionArgType.SP_POWER], METHOD_SAFE | EXTENDED);//引数が違うのでMETHOD化できない。
+			AddFunction(FunctionCode.PRINTCPERLINE, argb[FunctionArgType.SP_GETINT], METHOD_SAFE | EXTENDED);//よく考えたら引数の仕様違うや
+			AddFunction(FunctionCode.SAVENOS, argb[FunctionArgType.SP_GETINT], METHOD_SAFE | EXTENDED);//引数の仕様が違うので(ry
+			AddFunction(FunctionCode.ENCODETOUNI, argb[FunctionArgType.FORM_STR_NULLABLE], METHOD_SAFE | EXTENDED);//式中関数版を追加。処理が全然違う
+			#endregion
+
+			var methodList = FunctionMethodCreator.GetMethodList();
+			foreach (var pair in methodList)
+			{
+				var key = pair.Key;
+				if (!funcDic.ContainsKey(key))
+				{
+					funcDic.Add(key, new FunctionIdentifier(key, pair.Value, methodInstruction));
+				}
+			}
+			funcMatch[FunctionCode.IF] = "ENDIF";
+			funcMatch[FunctionCode.SELECTCASE] = "ENDSELECT";
+			funcMatch[FunctionCode.REPEAT] = "REND";
+			funcMatch[FunctionCode.FOR] = "NEXT";
+			funcMatch[FunctionCode.WHILE] = "WEND";
+			funcMatch[FunctionCode.TRYCGOTO] = "CATCH";
+			funcMatch[FunctionCode.TRYCJUMP] = "CATCH";
+			funcMatch[FunctionCode.TRYCCALL] = "CATCH";
+			funcMatch[FunctionCode.TRYCGOTOFORM] = "CATCH";
+			funcMatch[FunctionCode.TRYCJUMPFORM] = "CATCH";
+			funcMatch[FunctionCode.TRYCCALLFORM] = "CATCH";
+			funcMatch[FunctionCode.CATCH] = "ENDCATCH";
+			funcMatch[FunctionCode.DO] = "LOOP";
+			funcMatch[FunctionCode.PRINTDATA] = "ENDDATA";
+			funcMatch[FunctionCode.PRINTDATAL] = "ENDDATA";
+			funcMatch[FunctionCode.PRINTDATAW] = "ENDDATA";
+			funcMatch[FunctionCode.PRINTDATAK] = "ENDDATA";
+			funcMatch[FunctionCode.PRINTDATAKL] = "ENDDATA";
+			funcMatch[FunctionCode.PRINTDATAKW] = "ENDDATA";
+			funcMatch[FunctionCode.PRINTDATAD] = "ENDDATA";
+			funcMatch[FunctionCode.PRINTDATADL] = "ENDDATA";
+			funcMatch[FunctionCode.PRINTDATADW] = "ENDDATA";
+			funcMatch[FunctionCode.DATALIST] = "ENDLIST";
+			funcMatch[FunctionCode.STRDATA] = "ENDDATA";
+			funcMatch[FunctionCode.NOSKIP] = "ENDNOSKIP";
+			funcMatch[FunctionCode.TRYCALLLIST] = "ENDFUNC";
+			funcMatch[FunctionCode.TRYGOTOLIST] = "ENDFUNC";
+			funcMatch[FunctionCode.TRYJUMPLIST] = "ENDFUNC";
+			funcParent[FunctionCode.REND] = FunctionCode.REPEAT;
+			funcParent[FunctionCode.NEXT] = FunctionCode.FOR;
+			funcParent[FunctionCode.WEND] = FunctionCode.WHILE;
+			funcParent[FunctionCode.LOOP] = FunctionCode.DO;
+		}
+
+	    public static FunctionIdentifier SETFunction { get; }
+
+	    internal static string getMatchFunction(FunctionCode func)
+		{
+		    funcMatch.TryGetValue(func, out var ret);
+			return ret;
+		}
+
+
+		internal static FunctionCode getParentFunc(FunctionCode func)
+		{
+		    funcParent.TryGetValue(func, out var ret);
+			return ret;
+		}
+		#endregion
+
+		private FunctionIdentifier(string name, FunctionCode code, AbstractInstruction instruction)
+			: this(name, code, instruction, 0)
+		{
+		}
+		private FunctionIdentifier(string name, FunctionCode code, AbstractInstruction instruction, int additionalFlag)
+		{
+			Code = code;
+			ArgBuilder = instruction.ArgBuilder;
+			flag = instruction.Flag | additionalFlag;
+			Method = null;
+			Name = name;
+			Instruction = instruction;
+		}
+
+		private FunctionIdentifier(string name, FunctionCode code, ArgumentBuilder arg, int flag)
+		{
+			Code = code;
+			ArgBuilder = arg;
+			this.flag = flag;
+			Method = null;
+			Name = name;
+			Instruction = null;
+		}
+
+		private FunctionIdentifier(string methodName, FunctionMethod method, AbstractInstruction instruction)
+		{
+			Code = FunctionCode.__NULL__;
+			ArgBuilder = instruction.ArgBuilder;
+			flag = instruction.Flag;
+			Method = method;
+			Name = methodName;
+			Instruction = instruction;
+		}
+
+		public readonly AbstractInstruction Instruction;
+	    private readonly int flag;
+	    public FunctionCode Code { get; }
+	    public ArgumentBuilder ArgBuilder { get; }
+        public FunctionMethod Method { get; }
+	    public string Name { get; private set; }
+
+		internal bool IsFlowContorol()
+		{
+			return ((flag & FLOW_CONTROL) == FLOW_CONTROL);
+		}
+
+		internal bool IsExtended()
+		{
+			return ((flag & EXTENDED) == EXTENDED);
+		}
+
+		internal bool IsPrintDFunction()
+		{
+			return ((flag & ISPRINTDFUNC) == ISPRINTDFUNC);
+		}
+
+		internal bool IsPrintKFunction()
+		{
+			return ((flag & ISPRINTKFUNC) == ISPRINTKFUNC);
+		}
+
+		internal bool IsNewLine()
+		{
+			return ((flag & PRINT_NEWLINE) == PRINT_NEWLINE);
+		}
+
+		internal bool IsWaitInput()
+		{
+			return ((flag & PRINT_WAITINPUT) == PRINT_WAITINPUT);
+		}
+		internal bool IsPrintSingle()
+		{
+			return ((flag & PRINT_SINGLE) == PRINT_SINGLE);
+		}
+
+		internal bool IsPartial()
+		{
+			return ((flag & PARTIAL) == PARTIAL);
+		}
+
+		internal bool IsMethodSafe()
+		{
+			return ((flag & METHOD_SAFE) == METHOD_SAFE);
+		}
+
+		internal bool IsPrint()
+		{
+			return ((flag & IS_PRINT) == IS_PRINT);
+		}
+
+		internal bool IsInput()
+		{
+			return ((flag & IS_INPUT) == IS_INPUT);
+		}
+
+		internal bool IsPrintData()
+		{
+			return ((flag & IS_PRINTDATA) == IS_PRINTDATA);
+		}
+
+		internal bool IsForceSetArg()
+		{
+			return ((flag & FORCE_SETARG) == FORCE_SETARG);
+		}
+
+		internal bool IsDebug()
+		{
+			return ((flag & DEBUG_FUNC) == DEBUG_FUNC);
+		}
+
+		internal bool IsTry()
+		{
+			return ((flag & IS_TRY) == IS_TRY);
+		}
+
+		internal bool IsJump()
+		{
+			return ((flag & IS_JUMP) == IS_JUMP);
+		}
+
+		internal bool IsMethod()
+		{
+			return Method != null;
+		}
+
+		public override string ToString()
+		{
+			return Name;
+		}
+
+	}
+}

+ 2380 - 0
NTERA/Game/GameProc/Function/Instraction.Child.cs

@@ -0,0 +1,2380 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Text;
+using MinorShift.Emuera.GameData;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.GameData.Function;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.Sub;
+using MinorShift._Library;
+using NTERA.Game.Display;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera.GameProc.Function
+{
+	internal sealed partial class FunctionIdentifier
+	{
+		#region normalFunction
+		private sealed class PRINT_Instruction : AbstractInstruction
+		{
+			public PRINT_Instruction(string name)
+			{
+				//PRINT(|V|S|FORM|FORMS)(|K)(|D)(|L|W) コレと
+				//PRINTSINGLE(|V|S|FORM|FORMS)(|K)(|D) コレと
+				//PRINT(|FORM)(C|LC)(|K)(|D) コレ
+				//PRINTDATA(|K)(|D)(|L|W) ←は別クラス
+				flag = IS_PRINT;
+				var st = new StringStream(name);
+				st.Jump(5);//PRINT
+				if (st.CurrentEqualTo("SINGLE"))
+				{
+					flag |= PRINT_SINGLE | EXTENDED;
+					st.Jump(6);
+				}
+
+				if (st.CurrentEqualTo("V"))
+				{
+					ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_PRINTV);
+					isPrintV = true;
+					st.Jump(1);
+				}
+				else if (st.CurrentEqualTo("S"))
+				{
+					ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.STR_EXPRESSION);
+					st.Jump(1);
+				}
+				else if (st.CurrentEqualTo("FORMS"))
+				{
+					ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.STR_EXPRESSION);
+					isForms = true;
+					st.Jump(5);
+				}
+				else if (st.CurrentEqualTo("FORM"))
+				{
+					ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.FORM_STR_NULLABLE);
+					st.Jump(4);
+				}
+				else
+				{
+					ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.STR_NULLABLE);
+				}
+				if (st.CurrentEqualTo("LC"))
+				{
+					flag |= EXTENDED;
+					isLC = true;
+					st.Jump(2);
+				}
+				else if (st.CurrentEqualTo("C"))
+				{
+					if (name == "PRINTFORMC")
+						flag |= EXTENDED;
+					isC = true;
+					st.Jump(1);
+				}
+				if (st.CurrentEqualTo("K"))
+				{
+					flag |= ISPRINTKFUNC | EXTENDED;
+					st.Jump(1);
+				}
+				if (st.CurrentEqualTo("D"))
+				{
+					flag |= ISPRINTDFUNC | EXTENDED;
+					st.Jump(1);
+				}
+				if (st.CurrentEqualTo("L"))
+				{
+					flag |= PRINT_NEWLINE;
+					flag |= METHOD_SAFE;
+					st.Jump(1);
+				}
+				else if (st.CurrentEqualTo("W"))
+				{
+					flag |= PRINT_NEWLINE | PRINT_WAITINPUT;
+					st.Jump(1);
+				}
+				else
+				{
+					flag |= METHOD_SAFE;
+				}
+				if ((ArgBuilder == null) || (!st.EOS))
+					throw new ExeEE("PRINT異常");
+			}
+
+		    private readonly bool isPrintV;
+		    private readonly bool isLC;
+		    private readonly bool isC;
+		    private readonly bool isForms;
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				//Changes by Bartoum
+				
+				//All print lines are going trough here.
+				//This is where our chain of booleans is set to true.
+				
+				//A lot of function have tryTranslate or translate in their signatures
+				//This was added in the goal to know when translating is required or not.
+				
+				if (GlobalStatic.Process.SkipPrint)
+                    			return;
+
+				
+				exm.Console.UseUserStyle = true;
+				exm.Console.UseSetColorStyle = !func.Function.IsPrintDFunction();
+				string str = null;
+				if (func.Argument.IsConst) { 
+                    //Need to rework that part
+					str = func.Argument.ConstStr;
+                }
+				else if (isPrintV)
+				{
+					var builder = new StringBuilder();
+					var terms = ((SpPrintVArgument)func.Argument).Terms;
+					foreach (var termV in terms)
+					{
+					    builder.Append(termV.GetOperandType() == typeof(long)
+					        ? termV.GetIntValue(exm).ToString()
+					        : termV.GetStrValue(exm, translate));
+					}
+					str = builder.ToString();
+                    
+                }
+				else
+				{
+					str = ((ExpressionArgument)func.Argument).Term.GetStrValue(exm, translate);
+					if (isForms)
+					{
+						str = exm.CheckEscape(str);
+						var wt = LexicalAnalyzer.AnalyseFormattedString(new StringStream(str), FormStrEndWith.EoL, false);
+						var strForm = StrForm.FromWordToken(wt);
+						str = strForm.GetString(exm, translate);
+                    }
+                }
+				if (func.Function.IsPrintKFunction())
+					str = exm.ConvertStringType(str);
+				if (isC)
+					exm.Console.PrintC(str, true);
+				else if (isLC)
+					exm.Console.PrintC(str, false);
+				else
+					exm.OutputToConsole(str, func.Function);
+				exm.Console.UseSetColorStyle = true;
+			}
+		}
+
+		private sealed class PRINT_DATA_Instruction : AbstractInstruction
+		{
+			public PRINT_DATA_Instruction(string name)
+			{
+				//PRINTDATA(|K)(|D)(|L|W)
+				flag = EXTENDED | IS_PRINT | IS_PRINTDATA | PARTIAL;
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VAR_INT);
+				var st = new StringStream(name);
+				st.Jump(9);//PRINTDATA
+				if (st.CurrentEqualTo("K"))
+				{
+					flag |= ISPRINTKFUNC | EXTENDED;
+					st.Jump(1);
+				}
+				if (st.CurrentEqualTo("D"))
+				{
+					flag |= ISPRINTDFUNC | EXTENDED;
+					st.Jump(1);
+				}
+				if (st.CurrentEqualTo("L"))
+				{
+					flag |= PRINT_NEWLINE;
+					flag |= METHOD_SAFE;
+					st.Jump(1);
+				}
+				else if (st.CurrentEqualTo("W"))
+				{
+					flag |= PRINT_NEWLINE | PRINT_WAITINPUT;
+					st.Jump(1);
+				}
+				else
+				{
+					flag |= METHOD_SAFE;
+				}
+				if ((ArgBuilder == null) || (!st.EOS))
+					throw new ExeEE("PRINTDATA error");
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+                if (GlobalStatic.Process.SkipPrint)
+                    	return;
+				exm.Console.UseUserStyle = true;
+				exm.Console.UseSetColorStyle = !func.Function.IsPrintDFunction();
+				//表示データが空なら何もしないで飛ぶ
+				if (func.dataList.Count == 0)
+				{
+					state.JumpTo(func.JumpTo);
+					return;
+				}
+				var count = func.dataList.Count;
+				var choice = (int)exm.VEvaluator.GetNextRand(count);
+				var iTerm = ((PrintDataArgument)func.Argument).Var;
+			    iTerm?.SetValue(choice, exm); // this is a null propogation, though it looks extra weird here --Sworve
+			    var iList = func.dataList[choice];
+				var i = 0;
+			    foreach (var selectedLine in iList)
+				{
+					state.CurrentLine = selectedLine;
+					if (selectedLine.Argument == null)
+						ArgumentParser.SetArgumentTo(selectedLine);
+					var term = ((ExpressionArgument)selectedLine.Argument).Term;
+					var str = term.GetStrValue(exm);
+					if (func.Function.IsPrintKFunction())
+						str = exm.ConvertStringType(str);
+					exm.Console.Print(str);
+					if (++i < iList.Count)
+						exm.Console.NewLine();
+				}
+				if (func.Function.IsNewLine() || func.Function.IsWaitInput())
+				{
+					exm.Console.NewLine();
+					if (func.Function.IsWaitInput())
+						exm.Console.ReadAnyKey();
+				}
+				exm.Console.UseSetColorStyle = true;
+				//ジャンプするが、流れが連続であることを保証。
+				state.JumpTo(func.JumpTo);
+				//state.RunningLine = null;
+			}
+		}
+		
+		private sealed class HTML_PRINT_Instruction : AbstractInstruction
+		{
+		    private readonly bool _noNewLine;
+
+			public HTML_PRINT_Instruction(bool noLineBreaks = false)
+			{
+				flag = EXTENDED | METHOD_SAFE;
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.STR_EXPRESSION);
+                _noNewLine = noLineBreaks;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+                if (GlobalStatic.Process.SkipPrint)
+                   	return;
+				string str = null;
+				str = func.Argument.IsConst
+                    ? func.Argument.ConstStr
+                    : ((ExpressionArgument)func.Argument).Term.GetStrValue(exm, translate);
+				exm.Console.PrintHtml(str, _noNewLine);
+			}
+		}
+
+		private sealed class HTML_TAGSPLIT_Instruction : AbstractInstruction
+		{
+			public HTML_TAGSPLIT_Instruction()
+			{
+				flag = EXTENDED | METHOD_SAFE;
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_HTMLSPLIT);
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				var spSplitArg = (SpHtmlSplitArgument)func.Argument;
+				var str = spSplitArg.TargetStr.GetStrValue(exm);
+				var strs = HtmlManager.HtmlTagSplit(str);
+				
+				if (strs == null)
+				{
+					spSplitArg.Num.SetValue(-1, exm);
+					return;
+				}
+				
+				spSplitArg.Num.SetValue(strs.Length, exm);
+				var output = (string[])spSplitArg.Var.GetArray();
+				var outputlength = Math.Min(output.Length, strs.Length);
+				Array.Copy(strs, output, outputlength);
+			}
+		}
+		
+		
+		private sealed class PRINT_IMG_Instruction : AbstractInstruction
+		{
+			public PRINT_IMG_Instruction()
+			{
+				flag = EXTENDED | METHOD_SAFE;
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.STR_EXPRESSION);
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+                if (GlobalStatic.Process.SkipPrint)
+                    	return;
+			    var str = func.Argument.IsConst
+			        ? func.Argument.ConstStr
+			        : ((ExpressionArgument)func.Argument).Term.GetStrValue(exm);
+				exm.Console.PrintImg(str);
+			}
+		}
+
+		private sealed class PRINT_RECT_Instruction : AbstractInstruction
+		{
+			public PRINT_RECT_Instruction()
+			{
+				flag = EXTENDED | METHOD_SAFE;
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.INT_ANY);
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+                if (GlobalStatic.Process.SkipPrint)
+                    	return;
+				var intExpArg = (ExpressionArrayArgument)func.Argument;
+				var param = new int[intExpArg.TermList.Length];
+				for (int i = 0; i < intExpArg.TermList.Length; i++)
+					param[i] = toUInt32inArg(intExpArg.TermList[i].GetIntValue(exm), "PRINT_RECT", i + 1);
+
+				exm.Console.PrintShape("rect", param);
+			}
+		}
+
+		private sealed class PRINT_SPACE_Instruction : AbstractInstruction
+		{
+			public PRINT_SPACE_Instruction()
+			{
+				flag = EXTENDED | METHOD_SAFE;
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.INT_EXPRESSION);
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+                if (GlobalStatic.Process.SkipPrint)
+                    return;
+			    var param = func.Argument.IsConst 
+			        ? func.Argument.ConstInt 
+			        : ((ExpressionArgument)func.Argument).Term.GetIntValue(exm);
+				var param32 = toUInt32inArg(param, "PRINT_SPACE", 1);
+				exm.Console.PrintShape("space", new[] { param32 });
+			}
+		}
+
+		private sealed class DEBUGPRINT_Instruction : AbstractInstruction
+		{
+			public DEBUGPRINT_Instruction(bool form, bool newline)
+			{
+			    ArgBuilder = ArgumentParser.GetArgumentBuilder(form 
+                    ? FunctionArgType.FORM_STR_NULLABLE 
+                    : FunctionArgType.STR_NULLABLE);
+			    flag = METHOD_SAFE | EXTENDED | DEBUG_FUNC;
+				if (newline)
+					flag |= PRINT_NEWLINE;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				string str = null;
+				str = func.Argument.IsConst 
+                    ? func.Argument.ConstStr 
+                    : ((ExpressionArgument)func.Argument).Term.GetStrValue(exm);
+				exm.Console.DebugPrint(str);
+				if (func.Function.IsNewLine())
+					exm.Console.DebugNewLine();
+			}
+		}
+
+		private sealed class DEBUGCLEAR_Instruction : AbstractInstruction
+		{
+			public DEBUGCLEAR_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | EXTENDED | DEBUG_FUNC;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				exm.Console.DebugClear();
+			}
+		}
+
+		private sealed class METHOD_Instruction : AbstractInstruction
+		{
+			public METHOD_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.METHOD);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				IOperandTerm term = ((MethodArgument)func.Argument).MethodTerm;
+				Type type = term.GetOperandType();
+				if (term.GetOperandType() == typeof(Int64))
+					exm.VEvaluator.RESULT = term.GetIntValue(exm);
+				else// if (func.Argument.MethodTerm.GetOperandType() == typeof(string))
+					exm.VEvaluator.RESULTS = term.GetStrValue(exm);
+				//これら以外の型は現状ない
+				//else
+				//	throw new ExeEE(func.Function.Name + "命令の型が不明");
+			}
+		}
+
+		private sealed class SET_Instruction : AbstractInstruction
+		{
+			public SET_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_SET);
+				flag = METHOD_SAFE;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				if (func.Argument is SpSetArrayArgument)
+				{
+					SpSetArrayArgument arg = (SpSetArrayArgument)func.Argument;
+					if (arg.VariableDest.IsInteger)
+					{
+						if (arg.IsConst)
+							arg.VariableDest.SetValue(arg.ConstIntList, exm);
+						else
+						{
+							Int64[] values = new Int64[arg.TermList.Length];
+							for (int i = 0; i < values.Length; i++)
+							{
+								values[i] = arg.TermList[i].GetIntValue(exm);
+							}
+							arg.VariableDest.SetValue(values, exm);
+						}
+					}
+					else
+					{
+						if (arg.IsConst)
+							arg.VariableDest.SetValue(arg.ConstStrList, exm);
+						else
+						{
+							string[] values = new string[arg.TermList.Length];
+							for (int i = 0; i < values.Length; i++)
+							{
+								values[i] = arg.TermList[i].GetStrValue(exm, translate);
+							}
+							arg.VariableDest.SetValue(values, exm);
+						}
+					}
+					return;
+				}
+				SpSetArgument spsetarg = (SpSetArgument)func.Argument;
+				if (spsetarg.VariableDest.IsInteger)
+				{
+					Int64 src = spsetarg.IsConst ? spsetarg.ConstInt : spsetarg.Term.GetIntValue(exm);
+					if (spsetarg.AddConst)
+						spsetarg.VariableDest.PlusValue(src, exm);
+					else
+						spsetarg.VariableDest.SetValue(src, exm);
+				}
+				else
+				{
+					string src = spsetarg.IsConst ? spsetarg.ConstStr : spsetarg.Term.GetStrValue(exm, translate); // JVN: Should fix wrong STRLENS count for TR translated strings
+					spsetarg.VariableDest.SetValue(src, exm);
+                }
+			}
+		}
+
+		private sealed class REUSELASTLINE_Instruction : AbstractInstruction
+		{
+			public REUSELASTLINE_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.FORM_STR_NULLABLE);
+				flag = METHOD_SAFE | EXTENDED | IS_PRINT;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				IOperandTerm term = ((ExpressionArgument)func.Argument).Term;
+				string str = term.GetStrValue(exm);
+				exm.Console.PrintTemporaryLine(str);
+			}
+		}
+
+		private sealed class CLEARLINE_Instruction : AbstractInstruction
+		{
+			public CLEARLINE_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.INT_EXPRESSION);
+				flag = METHOD_SAFE | EXTENDED | IS_PRINT;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				ExpressionArgument intExpArg = (ExpressionArgument)func.Argument;
+				Int32 delNum = (Int32)intExpArg.Term.GetIntValue(exm);
+				exm.Console.deleteLine(delNum);
+				exm.Console.RefreshStrings(false);
+			}
+		}
+
+		private sealed class STRLEN_Instruction : AbstractInstruction
+		{
+			public STRLEN_Instruction(bool argisform, bool unicode)
+			{
+				if (argisform)
+					ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.FORM_STR_NULLABLE);
+				else
+					ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.STR_NULLABLE);
+				flag = METHOD_SAFE | EXTENDED;
+				this.unicode = unicode;
+			}
+			bool unicode;
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				string str = null;
+				if (func.Argument.IsConst)
+					str = func.Argument.ConstStr;
+				else
+					str = ((ExpressionArgument)func.Argument).Term.GetStrValue(exm);
+				if (unicode)
+					exm.VEvaluator.RESULT = str.Length;
+				else
+					exm.VEvaluator.RESULT = LangManager.GetStrlenLang(str);
+			}
+		}
+
+		private sealed class SETBIT_Instruction : AbstractInstruction
+		{
+			public SETBIT_Instruction(int op)
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.BIT_ARG);
+				flag = METHOD_SAFE | EXTENDED;
+				this.op = op;
+			}
+			int op;
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				BitArgument spsetarg = (BitArgument)func.Argument;
+				VariableTerm varTerm = spsetarg.VariableDest;
+				IOperandTerm[] terms = spsetarg.Term;
+				for (int i = 0; i < terms.Length; i++)
+				{
+					Int64 x = terms[i].GetIntValue(exm);
+					if ((x < 0) || (x > 63))
+						throw new CodeEE("第2引数がビットのレンジ(0から63)を超えています");
+					Int64 baseValue = varTerm.GetIntValue(exm);
+					Int64 shift = 1L << (int)x;
+					if (op == 1)
+						baseValue |= shift;
+					else if (op == 0)
+						baseValue &= ~shift;
+					else
+						baseValue ^= shift;
+					varTerm.SetValue(baseValue, exm);
+				}
+			}
+		}
+
+		private sealed class WAIT_Instruction : AbstractInstruction
+		{
+			public WAIT_Instruction(bool force)
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = IS_PRINT;
+				isForce = force;
+			}
+			bool isForce;
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				if (isForce)
+					exm.Console.ReadAnyKey(false, true);
+				else
+					exm.Console.ReadAnyKey();
+			}
+		}
+
+		private sealed class WAITANYKEY_Instruction : AbstractInstruction
+		{
+			public WAITANYKEY_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = IS_PRINT;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				exm.Console.ReadAnyKey(true,false);
+			}
+		}
+
+		private sealed class TWAIT_Instruction : AbstractInstruction
+		{
+			public TWAIT_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_SWAP);
+				flag = IS_PRINT | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				exm.Console.ReadAnyKey();
+				SpSwapCharaArgument arg = (SpSwapCharaArgument)func.Argument;
+				Int64 time = arg.X.GetIntValue(exm);
+				Int64 flag = arg.Y.GetIntValue(exm);
+				InputRequest req = new InputRequest();
+				req.InputType = InputType.EnterKey;
+				if (flag != 0)
+					req.InputType = InputType.Void;
+				req.Timelimit = time;
+				exm.Console.WaitInput(req);
+			}
+		}
+
+		private sealed class INPUT_Instruction : AbstractInstruction
+		{
+			public INPUT_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_INPUT);
+				flag = IS_PRINT | IS_INPUT;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				ExpressionArgument arg = (ExpressionArgument)func.Argument;
+				InputRequest req = new InputRequest();
+				req.InputType = InputType.IntValue;
+				if (arg.Term != null)
+				{
+					Int64 def;
+					if (arg.IsConst)
+						def = arg.ConstInt;
+					else
+						def = arg.Term.GetIntValue(exm);
+					req.HasDefValue = true;
+					req.DefIntValue = def;
+				}
+				exm.Console.WaitInput(req);
+			}
+		}
+		private sealed class INPUTS_Instruction : AbstractInstruction
+		{
+			public INPUTS_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_INPUTS);
+				flag = IS_PRINT | IS_INPUT;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				ExpressionArgument arg = (ExpressionArgument)func.Argument;
+				InputRequest req = new InputRequest();
+				req.InputType = InputType.StrValue;
+				if (arg.Term != null)
+				{
+					string def;
+					if (arg.IsConst)
+						def = arg.ConstStr;
+					else
+						def = arg.Term.GetStrValue(exm);
+					req.HasDefValue = true;
+					req.DefStrValue = def;
+				}
+				exm.Console.WaitInput(req);
+			}
+		}
+
+		private sealed class ONEINPUT_Instruction : AbstractInstruction
+		{
+			public ONEINPUT_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_INPUT);
+				flag = IS_PRINT | IS_INPUT | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				ExpressionArgument arg = (ExpressionArgument)func.Argument;
+				InputRequest req = new InputRequest();
+				req.InputType = InputType.IntValue;
+				req.OneInput = true;
+				if (arg.Term != null)
+				{
+					//TODO:二文字以上セットできるようにするかエラー停止するか
+					//少なくともONETINPUTとの仕様を統一すべき
+					Int64 def;
+					if (arg.IsConst)
+						def = arg.ConstInt;
+					else
+						def = arg.Term.GetIntValue(exm);
+					if (def > 9)
+						def = Int64.Parse(def.ToString().Remove(1));
+					if (def >= 0)
+					{
+						req.HasDefValue = true;
+						req.DefIntValue = def;
+					}
+				}
+				exm.Console.WaitInput(req);
+			}
+		}
+
+		private sealed class ONEINPUTS_Instruction : AbstractInstruction
+		{
+			public ONEINPUTS_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_INPUTS);
+				flag = IS_PRINT | IS_INPUT | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				ExpressionArgument arg = (ExpressionArgument)func.Argument;
+				InputRequest req = new InputRequest();
+				req.InputType = InputType.StrValue;
+				req.OneInput = true;
+				if (arg.Term != null)
+				{
+					string def;
+					if (arg.IsConst)
+						def = arg.ConstStr;
+					else
+						def = arg.Term.GetStrValue(exm);
+					if (def.Length > 1)
+						def = def.Remove(1);
+					if (def.Length > 0)
+					{
+						req.HasDefValue = true;
+						req.DefStrValue = def;
+					}
+				}
+				exm.Console.WaitInput(req);
+			}
+		}
+
+		private sealed class TINPUT_Instruction : AbstractInstruction
+		{
+			public TINPUT_Instruction(bool oneInput)
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_TINPUT);
+				flag = IS_PRINT | IS_INPUT | EXTENDED;
+				isOne = oneInput;
+			}
+			bool isOne;
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				SpTInputsArgument tinputarg = (SpTInputsArgument)func.Argument;
+
+				InputRequest req = new InputRequest();
+				req.InputType = InputType.IntValue;
+				req.HasDefValue = true;
+				req.OneInput = isOne;
+				Int64 x = tinputarg.Time.GetIntValue(exm);
+				Int64 y = tinputarg.Def.GetIntValue(exm);
+				//TODO:ONEINPUTと標準の値を統一
+				if (isOne)
+				{
+					if (y < 0)
+						y = Math.Abs(y);
+					if (y >= 10)
+						y = y / (long)(Math.Pow(10.0, Math.Log10(y)));
+				}
+				Int64 z = (tinputarg.Disp != null) ? tinputarg.Disp.GetIntValue(exm) : 1;
+				req.Timelimit = x;
+				req.DefIntValue = y;
+				req.DisplayTime = z != 0;
+				req.TimeUpMes = (tinputarg.Timeout != null) ? tinputarg.Timeout.GetStrValue(exm) : Config.TimeupLabel;
+				exm.Console.WaitInput(req);
+			}
+		}
+
+		private sealed class TINPUTS_Instruction : AbstractInstruction
+		{
+			public TINPUTS_Instruction(bool oneInput)
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_TINPUTS);
+				flag = IS_PRINT | IS_INPUT | EXTENDED;
+				isOne = oneInput;
+			}
+			bool isOne;
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				SpTInputsArgument tinputarg = (SpTInputsArgument)func.Argument;
+				InputRequest req = new InputRequest();
+				req.InputType = InputType.StrValue;
+				req.HasDefValue = true;
+				req.OneInput = isOne;
+				Int64 x = tinputarg.Time.GetIntValue(exm);
+				string strs = tinputarg.Def.GetStrValue(exm);
+				if (isOne && strs.Length > 1)
+					strs = strs.Remove(1);
+				Int64 z = (tinputarg.Disp != null) ? tinputarg.Disp.GetIntValue(exm) : 1;
+				req.Timelimit = x;
+				req.DefStrValue = strs;
+				req.DisplayTime = z != 0;
+				req.TimeUpMes = (tinputarg.Timeout != null) ? tinputarg.Timeout.GetStrValue(exm) : Config.TimeupLabel;
+				exm.Console.WaitInput(req);
+			}
+		}
+
+		private sealed class CALLF_Instruction : AbstractInstruction
+		{
+			public CALLF_Instruction(bool form)
+			{
+				if (form)
+					ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_CALLFORMF);
+				else
+					ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_CALLF);
+				flag = EXTENDED | METHOD_SAFE | FORCE_SETARG;
+			}
+
+			public override void SetJumpTo(ref bool useCallForm, InstructionLine func, int currentDepth, ref string FunctionoNotFoundName)
+			{
+				if (!func.Argument.IsConst)
+				{
+					useCallForm = true;
+					return;
+				}
+				SpCallFArgment callfArg = (SpCallFArgment)func.Argument;
+				if (Config.ICFunction)
+					callfArg.ConstStr = callfArg.ConstStr.ToUpper();
+				try
+				{
+					callfArg.FuncTerm = GlobalStatic.IdentifierDictionary.GetFunctionMethod(GlobalStatic.LabelDictionary, callfArg.ConstStr, callfArg.RowArgs, true);
+				}
+				catch (CodeEE e)
+				{
+					ParserMediator.Warn(e.Message, func, 2, true, false);
+					return;
+				}
+				if (callfArg.FuncTerm == null)
+				{
+					if (!Program.AnalysisMode)
+						ParserMediator.Warn("指定された関数名\"@" + callfArg.ConstStr + "\"は存在しません", func, 2, true, false);
+					else
+						ParserMediator.Warn(callfArg.ConstStr, func, 2, true, false);
+				}
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				IOperandTerm mToken = null;
+				string labelName = null;
+				if ((!func.Argument.IsConst) || (exm.Console.RunERBFromMemory))
+				{
+					SpCallFArgment spCallformArg = (SpCallFArgment)func.Argument;
+					labelName = spCallformArg.FuncnameTerm.GetStrValue(exm);
+					mToken = GlobalStatic.IdentifierDictionary.GetFunctionMethod(GlobalStatic.LabelDictionary, labelName, spCallformArg.RowArgs, true);
+				}
+				else
+				{
+					labelName = func.Argument.ConstStr;
+					mToken = ((SpCallFArgment)func.Argument).FuncTerm;
+				}
+				if (mToken == null)
+					throw new CodeEE("式中関数\"@" + labelName + "\"が見つかりません");
+				mToken.GetValue(exm);
+			}
+		}
+
+		private sealed class BAR_Instruction : AbstractInstruction
+		{
+			public BAR_Instruction(bool newline)
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_BAR);
+				flag = IS_PRINT | METHOD_SAFE | EXTENDED;
+				this.newline = newline;
+			}
+			bool newline;
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				SpBarArgument barArg = (SpBarArgument)func.Argument;
+				Int64 var = barArg.Terms[0].GetIntValue(exm);
+				Int64 max = barArg.Terms[1].GetIntValue(exm);
+				Int64 length = barArg.Terms[2].GetIntValue(exm);
+				exm.Console.Print(exm.CreateBar(var, max, length));
+				if (newline)
+					exm.Console.NewLine();
+			}
+		}
+		
+		private sealed class TIMES_Instruction : AbstractInstruction
+		{
+			public TIMES_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_TIMES);
+				flag = METHOD_SAFE;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				SpTimesArgument timesArg = (SpTimesArgument)func.Argument;
+				VariableTerm var = timesArg.VariableDest;
+                if (Config.TimesNotRigorousCalculation)
+                {
+                    double d = var.GetIntValue(exm) * timesArg.DoubleValue;
+                    unchecked
+                    {
+                        var.SetValue((Int64)d, exm);
+                    }
+                }
+                else
+                {
+                    decimal d = var.GetIntValue(exm) * (decimal)timesArg.DoubleValue;
+                    unchecked
+                    {
+                        //decimal型は強制的にOverFlowExceptionを投げるので対策が必要
+                        //OverFlowの場合は昔の挙動に近づけてみる
+                        if (d <= Int64.MaxValue && d >= Int64.MinValue)
+                            var.SetValue((Int64)d, exm);
+                        else
+                            var.SetValue((Int64)((double)d), exm);
+                    }
+                }
+			}
+		}
+
+
+		private sealed class ADDCHARA_Instruction : AbstractInstruction
+		{
+			public ADDCHARA_Instruction(bool flagSp, bool flagDel)
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.INT_ANY);
+				flag = METHOD_SAFE;
+				isDel = flagDel;
+				isSp = flagSp;
+			}
+			bool isDel;
+			bool isSp;
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				if(!Config.CompatiSPChara && isSp)
+					throw new CodeEE("SPキャラ関係の機能は標準では使用できません(互換性オプション「SPキャラを使用する」をONにしてください)");
+				ExpressionArrayArgument intExpArg = (ExpressionArrayArgument)func.Argument;
+				Int64 integer = -1;
+				Int64[] charaNoList = new Int64[intExpArg.TermList.Length];
+				int i = 0;
+				foreach (IOperandTerm int64Term in intExpArg.TermList)
+				{
+					integer = int64Term.GetIntValue(exm);
+					if (isDel)
+					{
+						charaNoList[i] = integer;
+						i++;
+					}
+					else
+					{
+						if(!Config.CompatiSPChara)
+							exm.VEvaluator.AddCharacter_UseSp(integer, isSp);
+						else
+							exm.VEvaluator.AddCharacter(integer);
+					}
+				}
+				if (isDel)
+				{
+					if(charaNoList.Length == 1)
+						exm.VEvaluator.DelCharacter(charaNoList[0]);
+					else
+						exm.VEvaluator.DelCharacter(charaNoList);
+				}
+			}
+		}
+
+		private sealed class ADDVOIDCHARA_Instruction : AbstractInstruction
+		{
+			public ADDVOIDCHARA_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				exm.VEvaluator.AddPseudoCharacter();
+			}
+		}
+
+		private sealed class SWAPCHARA_Instruction : AbstractInstruction
+		{
+			public SWAPCHARA_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_SWAP);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				SpSwapCharaArgument arg = (SpSwapCharaArgument)func.Argument;
+				long x = arg.X.GetIntValue(exm);
+				long y = arg.Y.GetIntValue(exm);
+				exm.VEvaluator.SwapChara(x, y);
+			}
+		}
+		private sealed class COPYCHARA_Instruction : AbstractInstruction
+		{
+			public COPYCHARA_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_SWAP);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				SpSwapCharaArgument arg = (SpSwapCharaArgument)func.Argument;
+				long x = arg.X.GetIntValue(exm);
+				long y = arg.Y.GetIntValue(exm);
+				exm.VEvaluator.CopyChara(x, y);
+			}
+		}
+
+		private sealed class ADDCOPYCHARA_Instruction : AbstractInstruction
+		{
+			public ADDCOPYCHARA_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.INT_ANY);
+				flag = METHOD_SAFE;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				ExpressionArrayArgument intExpArg = (ExpressionArrayArgument)func.Argument;
+				foreach (IOperandTerm int64Term in intExpArg.TermList)
+					exm.VEvaluator.AddCopyChara(int64Term.GetIntValue(exm));
+			}
+		}
+
+		private sealed class SORTCHARA_Instruction : AbstractInstruction
+		{
+			public SORTCHARA_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_SORTCHARA);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				SpSortcharaArgument spSortArg = (SpSortcharaArgument)func.Argument;
+				Int64 elem = 0;
+				VariableTerm sortKey = spSortArg.SortKey;
+				if (sortKey.Identifier.IsArray1D)
+					elem = sortKey.GetElementInt(1, exm);
+				else if (sortKey.Identifier.IsArray2D)
+				{
+					elem = sortKey.GetElementInt(1, exm) << 32;
+					elem += sortKey.GetElementInt(2, exm);
+				}
+
+				exm.VEvaluator.SortChara(sortKey.Identifier, elem, spSortArg.SortOrder, true);
+			}
+		}
+
+		private sealed class RESETCOLOR_Instruction : AbstractInstruction
+		{
+			public RESETCOLOR_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				exm.Console.SetStringStyle(Config.ForeColor);
+			}
+		}
+
+		private sealed class RESETBGCOLOR_Instruction : AbstractInstruction
+		{
+			public RESETBGCOLOR_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				exm.Console.SetBgColor(Config.BackColor);
+			}
+		}
+
+		private sealed class FONTBOLD_Instruction : AbstractInstruction
+		{
+			public FONTBOLD_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				exm.Console.SetStringStyle(exm.Console.StringStyle.FontStyle | FontStyle.Bold);
+			}
+		}
+		private sealed class FONTITALIC_Instruction : AbstractInstruction
+		{
+			public FONTITALIC_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				exm.Console.SetStringStyle(exm.Console.StringStyle.FontStyle | FontStyle.Italic);
+			}
+		}
+		private sealed class FONTREGULAR_Instruction : AbstractInstruction
+		{
+			public FONTREGULAR_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				exm.Console.SetStringStyle(FontStyle.Regular);
+			}
+		}
+
+		private sealed class VARSET_Instruction : AbstractInstruction
+		{
+			public VARSET_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_VAR_SET);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+
+				SpVarSetArgument spvarsetarg = (SpVarSetArgument)func.Argument;
+				VariableTerm var = spvarsetarg.VariableDest;
+				FixedVariableTerm p = var.GetFixedVariableTerm(exm);
+				int start = 0;
+				int end = 0;
+				//endを先に取って判定の処理変更
+				if (spvarsetarg.End != null)
+					end = (int)spvarsetarg.End.GetIntValue(exm);
+				else if (var.Identifier.IsArray1D)
+					end = var.GetLength();
+				if (spvarsetarg.Start != null)
+				{
+					start = (int)spvarsetarg.Start.GetIntValue(exm);
+					if (start > end)
+					{
+						int temp = start;
+						start = end;
+						end = start;
+					}
+				}
+				if (var.IsString)
+				{
+					string src = spvarsetarg.Term.GetStrValue(exm);
+					exm.VEvaluator.SetValueAll(p, src, start, end);
+				}
+				else
+				{
+					long src = spvarsetarg.Term.GetIntValue(exm);
+					exm.VEvaluator.SetValueAll(p, src, start, end);
+				}
+			}
+		}
+
+		private sealed class CVARSET_Instruction : AbstractInstruction
+		{
+			public CVARSET_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_CVAR_SET);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				SpCVarSetArgument spvarsetarg = (SpCVarSetArgument)func.Argument;
+				FixedVariableTerm p = spvarsetarg.VariableDest.GetFixedVariableTerm(exm);
+				SingleTerm index = spvarsetarg.Index.GetValue(exm);
+				int charaNum = (int)exm.VEvaluator.CHARANUM;
+				int start = 0;
+				if (spvarsetarg.Start != null)
+				{
+					start = (int)spvarsetarg.Start.GetIntValue(exm);
+					if (start < 0 || start >= charaNum)
+						throw new CodeEE("命令CVARSETの第4引数(" + start + ")がキャラクタの範囲外です");
+				}
+				int end = 0;
+				if (spvarsetarg.End != null)
+				{
+					end = (int)spvarsetarg.End.GetIntValue(exm);
+					if (end < 0 || end > charaNum)
+						throw new CodeEE("命令CVARSETの第5引数(" + end + ")がキャラクタの範囲外です");
+				}
+				else
+					end = charaNum;
+				if (start > end)
+				{
+					int temp = start;
+					start = end;
+					end = start;
+				}
+				if (!p.Identifier.IsCharacterData)
+					throw new CodeEE("命令CVARSETにキャラクタ変数でない変数" + p.Identifier.Name + "が渡されました");
+				if (index.GetOperandType() == typeof(string) && p.Identifier.IsArray1D)
+				{
+					if (!GlobalStatic.ConstantData.isDefined(p.Identifier.Code, index.Str))
+						throw new CodeEE("文字列" + index.Str + "は配列変数" + p.Identifier.Name + "の要素ではありません");
+				}
+				if (p.Identifier.IsString)
+				{
+					string src = spvarsetarg.Term.GetStrValue(exm);
+					exm.VEvaluator.SetValueAllEachChara(p, index, src, start, end);
+				}
+				else
+				{
+					long src = spvarsetarg.Term.GetIntValue(exm);
+					exm.VEvaluator.SetValueAllEachChara(p, index, src, start, end);
+				}
+			}
+		}
+
+		private sealed class RANDOMIZE_Instruction : AbstractInstruction
+		{
+			public RANDOMIZE_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.INT_EXPRESSION_NULLABLE);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				Int64 iValue;
+				if (func.Argument.IsConst)
+					iValue = func.Argument.ConstInt;
+				else
+					iValue = ((ExpressionArgument)func.Argument).Term.GetIntValue(exm);
+				exm.VEvaluator.Randomize(iValue);
+			}
+		}
+		private sealed class INITRAND_Instruction : AbstractInstruction
+		{
+			public INITRAND_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				exm.VEvaluator.InitRanddata();
+			}
+		}
+
+		private sealed class DUMPRAND_Instruction : AbstractInstruction
+		{
+			public DUMPRAND_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				exm.VEvaluator.DumpRanddata();
+			}
+		}
+
+
+		private sealed class SAVEGLOBAL_Instruction : AbstractInstruction
+		{
+			public SAVEGLOBAL_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				exm.VEvaluator.SaveGlobal();
+			}
+		}
+
+		private sealed class LOADGLOBAL_Instruction : AbstractInstruction
+		{
+			public LOADGLOBAL_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				if (exm.VEvaluator.LoadGlobal())
+					exm.VEvaluator.RESULT = 1;
+				else
+					exm.VEvaluator.RESULT = 0;
+			}
+		}
+
+		private sealed class RESETDATA_Instruction : AbstractInstruction
+		{
+			public RESETDATA_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				exm.VEvaluator.ResetData();
+				exm.Console.ResetStyle();
+			}
+		}
+
+		private sealed class RESETGLOBAL_Instruction : AbstractInstruction
+		{
+			public RESETGLOBAL_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				exm.VEvaluator.ResetGlobalData();
+			}
+		}
+
+		private static int toUInt32inArg(Int64 value, string funcName, int argnum)
+		{
+			if (value < 0)
+				throw new CodeEE(funcName + "の第" + argnum + "引数に負の値(" + value + ")が指定されました");
+			if (value > Int32.MaxValue)
+				throw new CodeEE(funcName + "の第" + argnum + "引数の値(" + value + ")が大きすぎます");
+
+			return (int)value;
+		}
+
+		private sealed class SAVECHARA_Instruction : AbstractInstruction
+		{
+			public SAVECHARA_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_SAVECHARA);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				ExpressionArrayArgument arg = (ExpressionArrayArgument)func.Argument;
+				IOperandTerm[] terms = arg.TermList;
+				string datFilename = terms[0].GetStrValue(exm);
+				string savMes = terms[1].GetStrValue(exm);
+				int[] savCharaList = new int[terms.Length - 2];
+				int charanum = (int)exm.VEvaluator.CHARANUM;
+				for (int i = 0; i < savCharaList.Length; i++)
+				{
+					Int64 v = terms[i + 2].GetIntValue(exm);
+					savCharaList[i] = toUInt32inArg(v, "SAVECHARA", i + 3);
+					if (savCharaList[i] >= charanum)
+						throw new CodeEE("SAVECHARAの第" + (i + 3) + "引数の値がキャラ登録番号の範囲を超えています");
+					for (int j = 0; j < i; j++)
+					{
+						if (savCharaList[i] == savCharaList[j])
+							throw new CodeEE("同一のキャラ登録番号(" + (savCharaList[i]) + ")が複数回指定されました");
+					}
+				}
+				exm.VEvaluator.SaveChara(datFilename, savMes, savCharaList);
+			}
+		}
+
+		private sealed class LOADCHARA_Instruction : AbstractInstruction
+		{
+			public LOADCHARA_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.STR_EXPRESSION);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				ExpressionArgument arg = (ExpressionArgument)func.Argument;
+				string datFilename = null;
+				if (arg.IsConst)
+					datFilename = arg.ConstStr;
+				else
+					datFilename = arg.Term.GetStrValue(exm);
+				exm.VEvaluator.LoadChara(datFilename);
+			}
+		}
+
+
+		private sealed class SAVEVAR_Instruction : AbstractInstruction
+		{
+			public SAVEVAR_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_SAVEVAR);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				throw new NotImplCodeEE();
+				//SpSaveVarArgument arg = (SpSaveVarArgument)func.Argument;
+				//VariableToken[] vars = arg.VarTokens;
+				//string datFilename = arg.Term.GetStrValue(exm);
+				//string savMes = arg.SavMes.GetStrValue(exm);
+				//exm.VEvaluator.SaveVariable(datFilename, savMes, vars);
+			}
+		}
+		private sealed class LOADVAR_Instruction : AbstractInstruction
+		{
+			public LOADVAR_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.STR_EXPRESSION);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				throw new NotImplCodeEE();
+				//ExpressionArgument arg = (ExpressionArgument)func.Argument;
+				//string datFilename = null;
+				//if (arg.IsConst)
+				//    datFilename = arg.ConstStr;
+				//else
+				//    datFilename = arg.Term.GetStrValue(exm);
+				//exm.VEvaluator.LoadVariable(datFilename);
+
+			}
+		}
+
+		private sealed class DELDATA_Instruction : AbstractInstruction
+		{
+			public DELDATA_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.INT_EXPRESSION);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				Int64 target;
+				if (func.Argument.IsConst)
+					target = func.Argument.ConstInt;
+				else
+					target = ((ExpressionArgument)func.Argument).Term.GetIntValue(exm);
+
+				int target32 = toUInt32inArg(target, "DELDATA", 1);
+				exm.VEvaluator.DelData(target32);
+			}
+		}
+
+		private sealed class DO_NOTHING_Instruction : AbstractInstruction
+		{
+			public DO_NOTHING_Instruction()
+			{
+				//事実上ENDIFの非フローコントロール版
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | EXTENDED | PARTIAL;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				//何もしない
+			}
+		}
+
+		private sealed class REF_Instruction : AbstractInstruction
+		{
+			public REF_Instruction(bool byname)
+			{
+				this.byname = byname;
+				if (byname)
+					ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_REFBYNAME);
+				else
+					ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_REF);
+
+				flag = METHOD_SAFE | EXTENDED;
+			}
+			bool byname;
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				throw new NotImplCodeEE();
+				RefArgument arg = (RefArgument)func.Argument;
+				string str = null;
+				if (arg.SrcTerm != null)
+					str = arg.SrcTerm.GetStrValue(exm);
+				if (arg.RefMethodToken != null)
+				{
+					UserDefinedRefMethod srcRef = arg.SrcRefMethodToken;
+					CalledFunction call = arg.SrcCalledFunction;
+					if (str != null)//REFBYNAMEかつ第二引数が定数でない
+					{
+						srcRef = GlobalStatic.IdentifierDictionary.GetRefMethod(str);
+						if (srcRef == null)
+						{
+							FunctionLabelLine label = GlobalStatic.LabelDictionary.GetNonEventLabel(str);
+							//if (label == null)
+							//    throw new CodeEE("式中関数" + str + "が見つかりません");
+							//if (!label.IsMethod)
+							//    throw new CodeEE("#FUNCTION(S)属性を持たない関数" + str + "は参照できません");
+							if (label != null && label.IsMethod)
+								call = CalledFunction.CreateCalledFunctionMethod(label, str);
+						}
+					}
+
+					if (srcRef != null)
+						call = srcRef.CalledFunction;//第二引数が関数参照。callがnullならエラー
+					if (call == null || !arg.RefMethodToken.MatchType(call))
+					{
+						arg.RefMethodToken.SetReference(null);
+						exm.VEvaluator.RESULT = 0;
+					}
+
+					arg.RefMethodToken.SetReference(call);
+					exm.VEvaluator.RESULT = 1;
+					return;
+				}
+
+				ReferenceToken refVar = arg.RefVarToken;
+				VariableToken srcVar = arg.SrcVarToken;
+				string errmes;
+				if (str != null)
+				{
+					srcVar = GlobalStatic.IdentifierDictionary.GetVariableToken(str, null, true);
+
+					//if (srcVar == null)
+					//    throw new CodeEE("変数" + str + "が見つかりません");
+				}
+				if (srcVar == null || !refVar.MatchType(srcVar, false, out errmes))
+				{
+					refVar.SetRef(null);
+					exm.VEvaluator.RESULT = 0;
+				}
+
+				refVar.SetRef((Array)srcVar.GetArray());
+				exm.VEvaluator.RESULT = 1;
+				return;
+			}
+		}
+
+		private sealed class TOOLTIP_SETCOLOR_Instruction : AbstractInstruction
+		{
+			public TOOLTIP_SETCOLOR_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_SWAP);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				SpSwapCharaArgument arg = (SpSwapCharaArgument)func.Argument;
+				long foreColor = arg.X.GetIntValue(exm);
+				long backColor = arg.Y.GetIntValue(exm);
+				if (foreColor < 0 || foreColor > 0xFFFFFF)
+					throw new CodeEE("第1引数が色を表す整数の範囲外です");
+				if (backColor < 0 || backColor > 0xFFFFFF)
+					throw new CodeEE("第2引数が色を表す整数の範囲外です");
+				Color fc = Color.FromArgb((int)foreColor >>16, (int)foreColor>>8 &0xFF,(int)foreColor &0xFF);
+				Color bc = Color.FromArgb((int)backColor >>16, (int)backColor>>8 &0xFF,(int)backColor &0xFF);
+				exm.Console.SetToolTipColor(fc, bc);
+			}
+		}
+
+		private sealed class TOOLTIP_SETDELAY_Instruction : AbstractInstruction
+		{
+			public TOOLTIP_SETDELAY_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.INT_EXPRESSION);
+				flag = METHOD_SAFE | EXTENDED;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				ExpressionArgument arg = (ExpressionArgument)func.Argument;
+				long delay = 0;
+				if(arg.IsConst)
+					delay = arg.ConstInt;
+				else
+					delay = arg.Term.GetIntValue(exm);
+				if (delay < 0 || delay > int.MaxValue)
+					throw new CodeEE("引数の値が適切な範囲外です");
+				exm.Console.SetToolTipDelay((int)delay);
+			}
+		}
+
+        private sealed class TOOLTIP_SETDURATION_Instruction : AbstractInstruction
+        {
+            public TOOLTIP_SETDURATION_Instruction()
+            {
+                ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.INT_EXPRESSION);
+                flag = METHOD_SAFE | EXTENDED;
+            }
+            public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+            {
+                ExpressionArgument arg = (ExpressionArgument)func.Argument;
+                long duration = 0;
+                if (arg.IsConst)
+                    duration = arg.ConstInt;
+                else
+                    duration = arg.Term.GetIntValue(exm);
+                if (duration < 0 || duration > int.MaxValue)
+                    throw new CodeEE("引数の値が適切な範囲外です");
+                if (duration > short.MaxValue)
+                    duration = short.MaxValue;
+                exm.Console.SetToolTipDuration((int)duration);
+            }
+        }
+
+		#endregion
+
+		#region flowControlFunction
+
+		private sealed class BEGIN_Instruction : AbstractInstruction
+		{
+			public BEGIN_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.STR);
+				flag = FLOW_CONTROL;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				string keyword = func.Argument.ConstStr;
+				if (Config.ICFunction)//1756 BEGINのキーワードは関数扱いらしい
+					keyword = keyword.ToUpper();
+				state.SetBegin(keyword);
+				state.Return(0);
+				exm.Console.ResetStyle();
+			}
+		}
+
+		private sealed class SAVELOADGAME_Instruction : AbstractInstruction
+		{
+			public SAVELOADGAME_Instruction(bool isSave)
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = FLOW_CONTROL;
+				this.isSave = isSave;
+			}
+			readonly bool isSave;
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				if ((state.SystemState & SystemStateCode.__CAN_SAVE__) != SystemStateCode.__CAN_SAVE__)
+				{
+					string funcName = state.Scope;
+					if (funcName == null)
+						funcName = "";
+					throw new CodeEE("@" + funcName + "中でSAVEGAME/LOADGAME命令を実行することはできません");
+				}
+				GlobalStatic.Process.saveCurrentState(true);
+				//バックアップに入れた旧ProcessStateの方を参照するため、ここでstateは使えない
+				GlobalStatic.Process.getCurrentState.SaveLoadData(isSave);
+			}
+		}
+
+		private sealed class REPEAT_Instruction : AbstractInstruction
+		{
+			public REPEAT_Instruction(bool fornext)
+			{
+				flag = METHOD_SAFE | FLOW_CONTROL | PARTIAL;
+				if (fornext)
+				{
+					ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_FOR_NEXT);
+					flag |= EXTENDED;
+				}
+				else
+				{
+					ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.INT_EXPRESSION);
+				}
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				SpForNextArgment forArg = (SpForNextArgment)func.Argument;
+				func.LoopCounter = forArg.Cnt;
+				//1.725 順序変更。REPEATにならう。
+				func.LoopCounter.SetValue(forArg.Start.GetIntValue(exm), exm);
+				func.LoopEnd = forArg.End.GetIntValue(exm);
+				func.LoopStep = forArg.Step.GetIntValue(exm);
+				if ((func.LoopStep > 0) && (func.LoopEnd > func.LoopCounter.GetIntValue(exm)))//まだ回数が残っているなら、
+					return;//そのまま次の行へ
+				if ((func.LoopStep < 0) && (func.LoopEnd < func.LoopCounter.GetIntValue(exm)))//まだ回数が残っているなら、
+					return;//そのまま次の行へ
+				state.JumpTo(func.JumpTo);
+			}
+		}
+
+		private sealed class WHILE_Instruction : AbstractInstruction
+		{
+			public WHILE_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.INT_EXPRESSION);
+				flag = METHOD_SAFE | EXTENDED | FLOW_CONTROL | PARTIAL;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				ExpressionArgument expArg = (ExpressionArgument)func.Argument;
+				if (expArg.Term.GetIntValue(exm) != 0)//式が真
+					return;//そのまま中の処理へ
+				state.JumpTo(func.JumpTo);
+			}
+		}
+
+		private sealed class SIF_Instruction : AbstractInstruction
+		{
+			public SIF_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.INT_EXPRESSION);
+				flag = METHOD_SAFE | FLOW_CONTROL | PARTIAL | FORCE_SETARG;
+			}
+
+			public override void SetJumpTo(ref bool useCallForm, InstructionLine func, int currentDepth, ref string FunctionoNotFoundName)
+			{
+				LogicalLine jumpto = func.NextLine;
+				if ((jumpto == null) || (jumpto.NextLine == null) ||
+					(jumpto is FunctionLabelLine) || (jumpto is NullLine))
+				{
+					ParserMediator.Warn("SIF文の次の行がありません", func, 2, true, false);
+					return;
+				}
+
+				if (jumpto is InstructionLine)
+				{
+					InstructionLine sifFunc = (InstructionLine)jumpto;
+					if (sifFunc.Function.IsPartial())
+						ParserMediator.Warn("SIF文の次の行を" + sifFunc.Function.Name + "文にすることはできません", func, 2, true, false);
+					else
+						func.JumpTo = func.NextLine.NextLine;
+				}
+				else if (jumpto is GotoLabelLine)
+					ParserMediator.Warn("SIF文の次の行をラベル行にすることはできません", func, 2, true, false);
+				else
+					func.JumpTo = func.NextLine.NextLine;
+
+				if ((func.JumpTo != null) && (func.Position.LineNo + 1 != func.NextLine.Position.LineNo))
+					ParserMediator.Warn("SIF文の次の行が空行またはコメント行です(eramaker:SIF文は意味を失います)", func, 0, false, true);
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				ExpressionArgument expArg = (ExpressionArgument)func.Argument;
+				if (expArg.Term.GetIntValue(exm) == 0)//評価式が真ならそのまま流れ落ちる
+					state.ShiftNextLine();//偽なら一行とばす。順に来たときと同じ扱いにする
+			}
+		}
+
+		private sealed class ELSEIF_Instruction : AbstractInstruction
+		{
+			public ELSEIF_Instruction(FunctionArgType argtype)
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(argtype);
+				flag = METHOD_SAFE | FLOW_CONTROL | PARTIAL | FORCE_SETARG;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				//if (iFuncCode == FunctionCode.ELSE || iFuncCode == FunctionCode.ELSEIF
+				//	|| iFuncCode == FunctionCode.CASE || iFuncCode == FunctionCode.CASEELSE)
+				//チェック済み
+				//if (func.JumpTo == null)
+				//	throw new ExeEE(func.Function.Name + "のジャンプ先が設定されていない");
+				state.JumpTo(func.JumpTo);
+			}
+		}
+		private sealed class ENDIF_Instruction : AbstractInstruction
+		{
+			public ENDIF_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = FLOW_CONTROL | PARTIAL | FORCE_SETARG;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+			}
+		}
+
+		private sealed class IF_Instruction : AbstractInstruction
+		{
+			public IF_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.INT_EXPRESSION);
+				flag = METHOD_SAFE | FLOW_CONTROL | PARTIAL | FORCE_SETARG;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				LogicalLine ifJumpto = func.JumpTo;//ENDIF
+				//チェック済み
+				//if (func.IfCaseList == null)
+				//	throw new ExeEE("IFのIF-ELSEIFリストが適正に作成されていない");
+				//if (func.JumpTo == null)
+				//	throw new ExeEE("IFに対応するENDIFが設定されていない");
+
+				InstructionLine line = null;
+				for (int i = 0; i < func.IfCaseList.Count; i++)
+				{
+					line = func.IfCaseList[i];
+					if (line.IsError)
+						continue;
+					if (line.FunctionCode == FunctionCode.ELSE)
+					{
+						ifJumpto = line;
+						break;
+					}
+
+					//ExpressionArgument expArg = (ExpressionArgument)(line.Argument);
+					//チェック済み
+					//if (expArg == null)
+					//	throw new ExeEE("IFチェック中。引数が解析されていない。", func.IfCaseList[i].Position);
+
+					//1730 ELSEIFが出したエラーがIFのエラーとして検出されていた
+					state.CurrentLine = line;
+					Int64 value = ((ExpressionArgument)(line.Argument)).Term.GetIntValue(exm);
+					if (value != 0)//式が真
+					{
+						ifJumpto = line;
+						break;
+					}
+				}
+				if (ifJumpto != func)//自分自身がジャンプ先ならそのまま
+					state.JumpTo(ifJumpto);
+				//state.RunningLine = null;
+			}
+		}
+
+
+		private sealed class SELECTCASE_Instruction : AbstractInstruction
+		{
+			public SELECTCASE_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.EXPRESSION);
+				flag = METHOD_SAFE | EXTENDED | FLOW_CONTROL | PARTIAL | FORCE_SETARG;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				LogicalLine caseJumpto = func.JumpTo;//ENDSELECT
+				IOperandTerm selectValue = ((ExpressionArgument)func.Argument).Term;
+				string sValue = null;
+				Int64 iValue = 0;
+				if (selectValue.IsInteger)
+					iValue = selectValue.GetIntValue(exm);
+				else
+					sValue = selectValue.GetStrValue(exm);
+				//チェック済み
+				//if (func.IfCaseList == null)
+				//	throw new ExeEE("SELECTCASEのCASEリストが適正に作成されていない");
+				//if (func.JumpTo == null)
+				//	throw new ExeEE("SELECTCASEに対応するENDSELECTが設定されていない");
+				InstructionLine line = null;
+				for (int i = 0; i < func.IfCaseList.Count; i++)
+				{
+					line = func.IfCaseList[i];
+					if (line.IsError)
+						continue;
+					if (line.FunctionCode == FunctionCode.CASEELSE)
+					{
+						caseJumpto = line;
+						break;
+					}
+					CaseArgument caseArg = (CaseArgument)(line.Argument);
+					//チェック済み
+					//if (caseArg == null)
+					//	throw new ExeEE("CASEチェック中。引数が解析されていない。", func.IfCaseList[i].Position);
+
+					state.CurrentLine = line;
+					if (selectValue.IsInteger)
+					{
+						Int64 Is = iValue;
+						foreach (CaseExpression caseExp in caseArg.CaseExps)
+						{
+							if (caseExp.GetBool(Is, exm))
+							{
+								caseJumpto = line;
+								goto casefound;
+							}
+						}
+					}
+					else
+					{
+						string Is = sValue;
+						foreach (CaseExpression caseExp in caseArg.CaseExps)
+						{
+							if (caseExp.GetBool(Is, exm))
+							{
+								caseJumpto = line;
+								goto casefound;
+							}
+						}
+					}
+
+				}
+			casefound:
+				state.JumpTo(caseJumpto);
+				//state.RunningLine = null;
+			}
+		}
+
+		private sealed class RETURNFORM_Instruction : AbstractInstruction
+		{
+			public RETURNFORM_Instruction()
+			{
+				//ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.FORM_STR_ANY);
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.FORM_STR);
+				flag = EXTENDED | FLOW_CONTROL;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				//int termnum = 0;
+				//foreach (IOperandTerm term in ((ExpressionArrayArgument)func.Argument).TermList)
+				//{
+				//    string arg = term.GetStrValue(exm);
+				//    StringStream aSt = new StringStream(arg);
+				//    WordCollection wc = LexicalAnalyzer.Analyse(aSt, LexEndWith.EoL, LexAnalyzeFlag.None);
+				//    exm.VEvaluator.SetResultX((ExpressionParser.ReduceIntegerTerm(wc, TermEndWith.EoL).GetIntValue(exm)), termnum);
+				//    termnum++;
+				//}
+				//state.Return(exm.VEvaluator.RESULT);
+				//if (state.ScriptEnd)
+				//    return;
+				//int termnum = 0;
+				StringStream aSt = new StringStream(((ExpressionArgument)func.Argument).Term.GetStrValue(exm));
+				List<long> termList = new List<long>();
+				while (!aSt.EOS)
+				{
+					WordCollection wc = LexicalAnalyzer.Analyse(aSt, LexEndWith.Comma, LexAnalyzeFlag.None);
+					//exm.VEvaluator.SetResultX(ExpressionParser.ReduceIntegerTerm(wc, TermEndWith.EoL).GetIntValue(exm), termnum++);
+					termList.Add(ExpressionParser.ReduceIntegerTerm(wc, TermEndWith.EoL).GetIntValue(exm));
+					aSt.ShiftNext();
+					LexicalAnalyzer.SkipHalfSpace(aSt);
+					//termnum++;
+				}
+				if (termList.Count == 0)
+					termList.Add(0);
+				exm.VEvaluator.SetResultX(termList);
+				state.Return(exm.VEvaluator.RESULT);
+				if (state.ScriptEnd)
+					return;
+			}
+		}
+
+		private sealed class RETURN_Instruction : AbstractInstruction
+		{
+			public RETURN_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.INT_ANY);
+				flag = FLOW_CONTROL;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				//int termnum = 0;
+				ExpressionArrayArgument expArrayArg = (ExpressionArrayArgument)func.Argument;
+				if (expArrayArg.TermList.Length == 0)
+				{
+					exm.VEvaluator.RESULT = 0;
+					state.Return(0);
+					return;
+				}
+				List<long> termList = new List<long>();
+				foreach (IOperandTerm term in expArrayArg.TermList)
+				{
+					termList.Add(term.GetIntValue(exm));
+					//exm.VEvaluator.SetResultX(term.GetIntValue(exm), termnum++);
+				}
+				if (termList.Count == 0)
+					termList.Add(0);
+				exm.VEvaluator.SetResultX(termList);
+				state.Return(exm.VEvaluator.RESULT);
+			}
+		}
+
+		private sealed class CATCH_Instruction : AbstractInstruction
+		{
+			public CATCH_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | EXTENDED | FLOW_CONTROL | PARTIAL;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				//if (sequential)//上から流れてきたなら何もしないでENDCATCHに飛ぶ
+				state.JumpTo(func.JumpToEndCatch);
+			}
+		}
+
+		private sealed class RESTART_Instruction : AbstractInstruction
+		{
+			public RESTART_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | FLOW_CONTROL | EXTENDED;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				state.JumpTo(func.ParentLabelLine);
+			}
+		}
+
+		private sealed class BREAK_Instruction : AbstractInstruction
+		{
+			public BREAK_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | FLOW_CONTROL;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				////BREAKのJUMP先はRENDまたはNEXT。そのジャンプ先であるREPEATかFORをiLineに代入。
+				//1.723 仕様変更。BREAKのJUMP先にはREPEAT、FOR、WHILEを記憶する。そのJUMP先が本当のJUMP先。
+				InstructionLine jumpTo = (InstructionLine)func.JumpTo;
+				InstructionLine iLine = (InstructionLine)jumpTo.JumpTo;
+				//WHILEとDOはカウンタがないので、即ジャンプ
+				if (jumpTo.FunctionCode != FunctionCode.WHILE && jumpTo.FunctionCode != FunctionCode.DO)
+				{
+					//eramakerではBREAK時にCOUNTが回る
+					jumpTo.LoopCounter.PlusValue(jumpTo.LoopStep, exm);
+				}
+				state.JumpTo(iLine);
+			}
+		}
+
+		private sealed class CONTINUE_Instruction : AbstractInstruction
+		{
+			public CONTINUE_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | FLOW_CONTROL;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				InstructionLine jumpTo = (InstructionLine)func.JumpTo;
+				if ((jumpTo.FunctionCode == FunctionCode.REPEAT) || (jumpTo.FunctionCode == FunctionCode.FOR))
+				{
+					//ループ変数が不明(REPEAT、FORを経由せずにループしようとした場合は無視してループを抜ける(eramakerがこういう仕様だったりする))
+					if (jumpTo.LoopCounter == null)
+					{
+						state.JumpTo(jumpTo.JumpTo);
+						return;
+					}
+
+					jumpTo.LoopCounter.PlusValue(jumpTo.LoopStep, exm);
+					Int64 counter = jumpTo.LoopCounter.GetIntValue(exm);
+					//まだ回数が残っているなら、
+					if (((jumpTo.LoopStep > 0) && (jumpTo.LoopEnd > counter))
+						|| ((jumpTo.LoopStep < 0) && (jumpTo.LoopEnd < counter)))
+						state.JumpTo(func.JumpTo);
+					else
+						state.JumpTo(jumpTo.JumpTo);
+					return;
+				}
+				if (jumpTo.FunctionCode == FunctionCode.WHILE)
+				{
+					if (((ExpressionArgument)jumpTo.Argument).Term.GetIntValue(exm) != 0)
+						state.JumpTo(func.JumpTo);
+					else
+						state.JumpTo(jumpTo.JumpTo);
+					return;
+				}
+				if (jumpTo.FunctionCode == FunctionCode.DO)
+				{
+					//こいつだけはCONTINUEよりも後ろに判定行があるため、判定行にエラーがあった場合に問題がある
+					InstructionLine tFunc = (InstructionLine)((InstructionLine)func.JumpTo).JumpTo;//LOOP
+					if (tFunc.IsError)
+						throw new CodeEE(tFunc.ErrMes, tFunc.Position);
+					ExpressionArgument expArg = (ExpressionArgument)tFunc.Argument;
+					if (expArg.Term.GetIntValue(exm) != 0)//式が真
+						state.JumpTo(jumpTo);//DO
+					else
+						state.JumpTo(tFunc);//LOOP
+					return;
+				}
+				throw new ExeEE("異常なCONTINUE");
+			}
+		}
+
+		private sealed class REND_Instruction : AbstractInstruction
+		{
+			public REND_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | FLOW_CONTROL | PARTIAL;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				InstructionLine jumpTo = (InstructionLine)func.JumpTo;
+				//ループ変数が不明(REPEAT、FORを経由せずにループしようとした場合は無視してループを抜ける(eramakerがこういう仕様だったりする))
+				if (jumpTo.LoopCounter == null)
+				{
+					state.JumpTo(jumpTo.JumpTo);
+					return;
+				}
+
+				jumpTo.LoopCounter.PlusValue(jumpTo.LoopStep, exm);
+				Int64 counter = jumpTo.LoopCounter.GetIntValue(exm);
+				//まだ回数が残っているなら、
+				if (((jumpTo.LoopStep > 0) && (jumpTo.LoopEnd > counter))
+					|| ((jumpTo.LoopStep < 0) && (jumpTo.LoopEnd < counter)))
+					state.JumpTo(func.JumpTo);
+			}
+		}
+
+		private sealed class WEND_Instruction : AbstractInstruction
+		{
+			public WEND_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.VOID);
+				flag = METHOD_SAFE | EXTENDED | FLOW_CONTROL | PARTIAL;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				InstructionLine jumpTo = (InstructionLine)func.JumpTo;
+				if (((ExpressionArgument)jumpTo.Argument).Term.GetIntValue(exm) != 0)
+					state.JumpTo(func.JumpTo);
+			}
+		}
+
+		private sealed class LOOP_Instruction : AbstractInstruction
+		{
+			public LOOP_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.INT_EXPRESSION);
+				flag = METHOD_SAFE | EXTENDED | FLOW_CONTROL | PARTIAL | FORCE_SETARG;
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				ExpressionArgument expArg = (ExpressionArgument)func.Argument;
+				if (expArg.Term.GetIntValue(exm) != 0)//式が真
+					state.JumpTo(func.JumpTo);
+			}
+		}
+
+
+		private sealed class RETURNF_Instruction : AbstractInstruction
+		{
+			public RETURNF_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.EXPRESSION_NULLABLE);
+				flag = METHOD_SAFE | EXTENDED | FLOW_CONTROL;
+			}
+
+			public override void SetJumpTo(ref bool useCallForm, InstructionLine func, int currentDepth, ref string FunctionoNotFoundName)
+			{
+				FunctionLabelLine label = func.ParentLabelLine;
+				if (!label.IsMethod)
+				{
+					ParserMediator.Warn("RETURNFは#FUNCTION以外では使用できません", func, 2, true, false);
+				}
+				if (func.Argument != null)
+				{
+					IOperandTerm term = ((ExpressionArgument)func.Argument).Term;
+					if (term != null)
+					{
+						if (label.MethodType != term.GetOperandType())
+						{
+							if (label.MethodType == typeof(Int64))
+								ParserMediator.Warn("#FUNCTIONで始まる関数の戻り値に文字列型が指定されました", func, 2, true, false);
+							else if (label.MethodType == typeof(string))
+								ParserMediator.Warn("#FUCNTIONSで始まる関数の戻り値に数値型が指定されました", func, 2, true, false);
+						}
+					}
+				}
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				IOperandTerm term = ((ExpressionArgument)func.Argument).Term;
+				SingleTerm ret = null;
+				if (term != null)
+				{
+					ret = term.GetValue(exm, translate);
+				}
+				state.ReturnF(ret);
+			}
+		}
+
+		private sealed class CALL_Instruction : AbstractInstruction
+		{
+			public CALL_Instruction(bool form, bool isJump, bool isTry, bool isTryCatch)
+			{
+				if (form)
+					ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_CALLFORM);
+				else
+					ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_CALL);
+				flag = FLOW_CONTROL | FORCE_SETARG;
+				if (isJump)
+					flag |= IS_JUMP;
+				if (isTry)
+					flag |= IS_TRY;
+				if (isTryCatch)
+					flag |= IS_TRYC | PARTIAL;
+				this.isJump = isJump;
+				this.isTry = isTry;
+			}
+			readonly bool isJump;
+			readonly bool isTry;
+
+			public override void SetJumpTo(ref bool useCallForm, InstructionLine func, int currentDepth, ref string FunctionoNotFoundName)
+			{
+				if (!func.Argument.IsConst)
+				{
+					useCallForm = true;
+					return;
+				}
+				SpCallArgment callArg = (SpCallArgment)func.Argument;
+				string labelName = callArg.ConstStr;
+				if (Config.ICFunction)
+					labelName = labelName.ToUpper();
+				CalledFunction call = CalledFunction.CallFunction(GlobalStatic.Process, labelName, func);
+				if ((call == null) && (!func.Function.IsTry()))
+				{
+					FunctionoNotFoundName = labelName;
+					return;
+				}
+				if (call != null)
+				{
+					func.JumpTo = call.TopLabel;
+					if (call.TopLabel.Depth < 0)
+						call.TopLabel.Depth = currentDepth + 1;
+					if (call.TopLabel.IsError)
+					{
+						func.IsError = true;
+						func.ErrMes = call.TopLabel.ErrMes;
+						return;
+					}
+					string errMes;
+					callArg.UDFArgument = call.ConvertArg(callArg.RowArgs, out errMes);
+					if (callArg.UDFArgument == null)
+					{
+						ParserMediator.Warn(errMes, func, 2, true, false);
+						return;
+					}
+				}
+				callArg.CallFunc = call;
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				SpCallArgment spCallArg = (SpCallArgment)func.Argument;
+				CalledFunction call = null;
+				string labelName = null;
+				UserDefinedFunctionArgument arg = null;
+				if (spCallArg.IsConst)
+				{
+					call = spCallArg.CallFunc;
+					labelName = spCallArg.ConstStr;
+					arg = spCallArg.UDFArgument;
+				}
+				else
+				{
+					labelName = spCallArg.FuncnameTerm.GetStrValue(exm);
+					if (Config.ICFunction)
+						labelName = labelName.ToUpper();
+					call = CalledFunction.CallFunction(GlobalStatic.Process, labelName, func);
+				}
+				if (call == null)
+				{
+					if (!isTry)
+						throw new CodeEE("関数\"@" + labelName + "\"が見つかりません");
+					if (func.JumpToEndCatch != null)
+						state.JumpTo(func.JumpToEndCatch);
+					return;
+				}
+				call.IsJump = isJump;
+				if (arg == null)
+				{
+					string errMes;
+					arg = call.ConvertArg(spCallArg.RowArgs, out errMes);
+					if (arg == null)
+						throw new CodeEE(errMes);
+				}
+				state.IntoFunction(call, arg, exm);
+			}
+		}
+
+		private sealed class CALLEVENT_Instruction : AbstractInstruction
+		{
+			public CALLEVENT_Instruction()
+			{
+				ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.STR);
+				flag = FLOW_CONTROL | EXTENDED;
+			}
+
+			public override void SetJumpTo(ref bool useCallForm, InstructionLine func, int currentDepth, ref string FunctionoNotFoundName)
+			{
+				//EVENT関数からCALLされた先でCALLEVENTされるようなパターンはIntoFunctionで捕まえる
+				FunctionLabelLine label = func.ParentLabelLine;
+				if (label.IsEvent)
+				{
+					ParserMediator.Warn("EVENT関数中にCALLEVENT命令は使用できません", func, 2, true, false);
+				}
+			}
+
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				string labelName = func.Argument.ConstStr;
+				if (Config.ICFunction)
+					labelName = labelName.ToUpper();
+				CalledFunction call = CalledFunction.CallEventFunction(GlobalStatic.Process, labelName, func);
+				if (call == null)
+					return;
+				state.IntoFunction(call, null, null);
+			}
+		}
+
+		private sealed class GOTO_Instruction : AbstractInstruction
+		{
+			public GOTO_Instruction(bool form, bool isTry, bool isTryCatch)
+			{
+				if (form)
+					ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_CALLFORM);
+				else
+					ArgBuilder = ArgumentParser.GetArgumentBuilder(FunctionArgType.SP_CALL);
+				this.isTry = isTry;
+				flag = METHOD_SAFE | FLOW_CONTROL | FORCE_SETARG;
+				if (isTry)
+					flag |= IS_TRY;
+				if (isTryCatch)
+					flag |= IS_TRYC | PARTIAL;
+			}
+			readonly bool isTry;
+
+			public override void SetJumpTo(ref bool useCallForm, InstructionLine func, int currentDepth, ref string FunctionoNotFoundName)
+			{
+				GotoLabelLine jumpto = null;
+				func.JumpTo = null;
+				if (func.Argument.IsConst)
+				{
+					string labelName = func.Argument.ConstStr;
+					if (Config.ICVariable)//eramakerではGOTO文は大文字小文字を区別しない
+						labelName = labelName.ToUpper();
+					jumpto = GlobalStatic.LabelDictionary.GetLabelDollar(labelName, func.ParentLabelLine);
+					if (jumpto == null)
+					{
+						if (!func.Function.IsTry())
+							ParserMediator.Warn("指定されたラベル名\"$" + labelName + "\"は現在の関数内に存在しません", func, 2, true, false);
+						else
+							return;
+					}
+					else if (jumpto.IsError)
+						ParserMediator.Warn("指定されたラベル名\"$" + labelName + "\"は無効な$ラベル行です", func, 2, true, false);
+					else if (jumpto != null)
+					{
+						func.JumpTo = jumpto;
+					}
+				}
+			}
+			public override void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+			{
+				string label = null;
+				LogicalLine jumpto = null;
+				if (func.Argument.IsConst)
+				{
+					label = func.Argument.ConstStr;
+					if (func.JumpTo != null)
+						jumpto = func.JumpTo;
+					else
+						return;
+				}
+				else
+				{
+					label = ((SpCallArgment)func.Argument).FuncnameTerm.GetStrValue(exm);
+					if (Config.ICVariable)
+						label = label.ToUpper();
+					jumpto = state.CurrentCalled.CallLabel(GlobalStatic.Process, label);
+				}
+				if (jumpto == null)
+				{
+					if (!func.Function.IsTry())
+						throw new CodeEE("指定されたラベル名\"$" + label + "\"は現在の関数内に存在しません");
+					if (func.JumpToEndCatch != null)
+						state.JumpTo(func.JumpToEndCatch);
+					return;
+				}
+
+				if (jumpto.IsError)
+					throw new CodeEE("指定されたラベル名\"$" + label + "\"は無効な$ラベル行です");
+				state.JumpTo(jumpto);
+			}
+		}
+		#endregion
+	}
+}

+ 24 - 0
NTERA/Game/GameProc/Function/Instruction.cs

@@ -0,0 +1,24 @@
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameProc.Function
+{
+
+	internal abstract class AbstractInstruction
+	{
+	    protected int flag;
+	    public int Flag => flag;
+
+		public ArgumentBuilder ArgBuilder {get; protected set;}
+	    public virtual void SetJumpTo(ref bool useCallForm, InstructionLine func, int currentDepth, ref string FunctionoNotFoundName) { }
+	    public virtual void DoInstruction(ExpressionMediator exm, InstructionLine func, ProcessState state, bool translate = false)
+		{ throw new ExeEE("未実装 or 呼び出しミス"); }
+		
+		public virtual Argument CreateArgument(InstructionLine line, ExpressionMediator exm)
+		{
+			throw new ExeEE("実装されていない");
+		}
+			
+	}
+	
+}

+ 253 - 0
NTERA/Game/GameProc/HeaderFileLoader.cs

@@ -0,0 +1,253 @@
+using System.Collections.Generic;
+using System.Windows.Forms;
+using MinorShift.Emuera.GameData;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.Sub;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera.GameProc
+{
+	internal sealed class HeaderFileLoader
+	{
+		public HeaderFileLoader(IConsole main, IdentifierDictionary idDic, Process proc)
+		{
+			output = main;
+			parentProcess = proc;
+			this.idDic = idDic;
+		}
+		readonly Process parentProcess;
+		readonly IConsole output;
+		readonly IdentifierDictionary idDic;
+
+		bool noError = true;
+		/// <summary>
+		/// 
+		/// </summary>
+		/// <param name="erbDir"></param>
+		/// <param name="displayReport"></param>
+		/// <returns></returns>
+		public bool LoadHeaderFiles(string headerDir, bool displayReport)
+		{
+			List<KeyValuePair<string, string>> headerFiles = Config.GetFiles(headerDir, "*.ERH");
+			bool noError = true;
+			try
+			{
+				for (int i = 0; i < headerFiles.Count; i++)
+				{
+					string filename = headerFiles[i].Key;
+					string file = headerFiles[i].Value;
+					if (displayReport)
+						output.PrintSystemLine("Loading " + filename + "...");
+					noError = loadHeaderFile(file, filename);
+					if (!noError)
+						break;
+					Application.DoEvents();
+				}
+			}
+			finally
+			{
+				ParserMediator.FlushWarningList();
+			}
+			return noError;
+		}
+
+
+		private bool loadHeaderFile(string filepath, string filename)
+		{
+			StringStream st = null;
+			ScriptPosition position = null;
+			//EraStreamReader eReader = new EraStreamReader(false);
+			//1815修正 _rename.csvの適用
+			//eramakerEXの仕様的には.ERHに適用するのはおかしいけど、もうEmueraの仕様になっちゃってるのでしかたないか
+			EraStreamReader eReader = new EraStreamReader(true);
+
+			if (!eReader.Open(filepath, filename))
+			{
+				throw new CodeEE(eReader.Filename + "のオープンに失敗しました");
+				//return false;
+			}
+			try
+			{
+				while ((st = eReader.ReadEnabledLine()) != null)
+				{
+					if (!noError)
+						return false;
+					position = new ScriptPosition(filename, eReader.LineNo, st.RowString);
+					LexicalAnalyzer.SkipWhiteSpace(st);
+					if (st.Current != '#')
+						throw new CodeEE("ヘッダーの中に#で始まらない行があります", position);
+					st.ShiftNext();
+					string sharpID = LexicalAnalyzer.ReadSingleIdentifier(st);
+					if (sharpID == null)
+					{
+						ParserMediator.Warn("解釈できない#行です", position, 1);
+						return false;
+					}
+					if (Config.ICFunction)
+						sharpID = sharpID.ToUpper();
+					LexicalAnalyzer.SkipWhiteSpace(st);
+					switch (sharpID)
+					{
+						case "DEFINE":
+							analyzeSharpDefine(st, position);
+							break;
+						case "FUNCTION":
+						case "FUNCTIONS":
+							analyzeSharpFunction(st, position, sharpID == "FUNCTIONS");
+							break;
+						case "DIM":
+						case "DIMS":
+							analyzeSharpDim(st, position, sharpID == "DIMS");
+							break;
+						default:
+							throw new CodeEE("#" + sharpID + "は解釈できないプリプロセッサです", position);
+					}
+				}
+			}
+			catch (CodeEE e)
+			{
+				if (e.Position != null)
+					position = e.Position;
+				ParserMediator.Warn(e.Message, position, 2);
+				return false;
+			}
+			finally
+			{
+				eReader.Close();
+			}
+			return true;
+		}
+
+		//#define FOO (~~)     id to wc
+		//#define BAR($1) (~~)     idwithargs to wc(replaced)
+		//#diseble FOOBAR             
+		//#dim piyo, i
+		//#dims puyo, j
+		//static List<string> keywordsList = new List<string>();
+
+		private void analyzeSharpDefine(StringStream st, ScriptPosition position)
+		{
+			//LexicalAnalyzer.SkipWhiteSpace(st);呼び出し前に行う。
+			string srcID = LexicalAnalyzer.ReadSingleIdentifier(st);
+			if (srcID == null)
+				throw new CodeEE("置換元の識別子がありません", position);
+			if (Config.ICVariable)
+				srcID = srcID.ToUpper();
+
+            //ここで名称重複判定しないと、大変なことになる
+            string errMes = "";
+            int errLevel = -1;
+            idDic.CheckUserMacroName(ref errMes, ref errLevel, srcID);
+            if (errLevel >= 0)
+            {
+                ParserMediator.Warn(errMes, position, errLevel);
+                if (errLevel >= 2)
+                {
+                    noError = false;
+                    return;
+                }
+            }
+            
+            bool hasArg = st.Current == '(';//引数を指定する場合には直後に(が続いていなければならない。ホワイトスペースも禁止。
+			//1808a3 代入演算子許可(関数宣言用)
+			WordCollection wc = LexicalAnalyzer.Analyse(st, LexEndWith.EoL, LexAnalyzeFlag.AllowAssignment);
+			if (wc.EOL)
+			{
+				//throw new CodeEE("置換先の式がありません", position);
+				//1808a3 空マクロの許可
+				DefineMacro nullmac = new DefineMacro(srcID, new WordCollection(), 0);
+				idDic.AddMacro(nullmac);
+				return;
+			}
+
+			List<string> argID = new List<string>();
+			if (hasArg)//関数型マクロの引数解析
+			{
+				wc.ShiftNext();//'('を読み飛ばす
+				if (wc.Current.Type == ')')
+					throw new CodeEE("関数型マクロの引数を0個にすることはできません", position);
+				while (!wc.EOL)
+				{
+					IdentifierWord word = wc.Current as IdentifierWord;
+					if (word == null)
+						throw new CodeEE("置換元の引数指定の書式が間違っています", position);
+					word.SetIsMacro();
+					string id = word.Code;
+					if (argID.Contains(id))
+						throw new CodeEE("置換元の引数に同じ文字が2回以上使われています", position);
+					argID.Add(id);
+					wc.ShiftNext();
+					if (wc.Current.Type == ',')
+					{
+						wc.ShiftNext();
+						continue;
+					}
+					if (wc.Current.Type == ')')
+						break;
+					throw new CodeEE("置換元の引数指定の書式が間違っています", position);
+				}
+				if (wc.EOL)
+					throw new CodeEE("')'が閉じられていません", position);
+
+				wc.ShiftNext();
+			}
+			if (wc.EOL)
+				throw new CodeEE("置換先の式がありません", position);
+			WordCollection destWc = new WordCollection();
+			while (!wc.EOL)
+			{
+				destWc.Add(wc.Current);
+				wc.ShiftNext();
+			}
+			if (hasArg)//関数型マクロの引数セット
+			{
+				while (!destWc.EOL)
+				{
+					IdentifierWord word = destWc.Current as IdentifierWord;
+					if (word == null)
+					{
+						destWc.ShiftNext();
+						continue;
+					}
+					for (int i = 0; i < argID.Count; i++)
+					{
+						if (string.Equals(word.Code, argID[i], Config.SCVariable))
+						{
+							destWc.Remove();
+							destWc.Insert(new MacroWord(i));
+							break;
+						}
+					}
+					destWc.ShiftNext();
+				}
+				destWc.Pointer = 0;
+			}
+			if (hasArg)//1808a3 関数型マクロの封印
+				throw new CodeEE("関数型マクロは宣言できません", position);
+			DefineMacro mac = new DefineMacro(srcID, destWc, argID.Count);
+			idDic.AddMacro(mac);
+		}
+
+		private void analyzeSharpDim(StringStream st, ScriptPosition position, bool dims)
+		{
+			WordCollection wc = LexicalAnalyzer.Analyse(st, LexEndWith.EoL, LexAnalyzeFlag.AllowAssignment);
+			UserDefinedVariableData data = UserDefinedVariableData.Create(wc, dims, false, position);
+			if (data.Reference)
+				throw new NotImplCodeEE();
+			VariableToken var = null;
+			if (data.CharaData)
+				var = parentProcess.VEvaluator.VariableData.CreateUserDefCharaVariable(data);
+			else
+				var = parentProcess.VEvaluator.VariableData.CreateUserDefVariable(data);
+			idDic.AddUseDefinedVariable(var);
+		}
+
+		private void analyzeSharpFunction(StringStream st, ScriptPosition position, bool funcs)
+		{
+			throw new NotImplCodeEE();
+			//WordCollection wc = LexicalAnalyzer.Analyse(st, LexEndWith.EoL, LexAnalyzeFlag.AllowAssignment);
+			//UserDefinedFunctionData data = UserDefinedFunctionData.Create(wc, funcs, position);
+			//idDic.AddRefMethod(UserDefinedRefMethod.Create(data));
+		}
+	}
+}

+ 42 - 0
NTERA/Game/GameProc/InputRequest.cs

@@ -0,0 +1,42 @@
+using System;
+
+namespace MinorShift.Emuera.GameProc
+{
+	public enum InputType
+	{
+		EnterKey = 1,//Enterキーかクリック
+		AnyKey = 2,//なんでもいいから入力
+		IntValue = 3,//整数値。OneInputかどうかは別の変数で
+		StrValue = 4,//文字列。
+		Void = 5//入力不能。待つしかない→スキップ中orマクロ中ならなかったことになる
+	}
+	
+
+	// 1819追加 入力・表示系とData、Process系の結合を弱くしよう計画の一つ
+	// できるだけ間にクッションをおいていきたい。最終的には別スレッドに
+
+	//クラスを毎回使い捨てるのはどうなんだろう 使いまわすべきか
+	public sealed class InputRequest
+	{
+		public InputRequest()
+		{
+			ID = LastRequestID++;
+		}
+		public readonly Int64 ID;
+		public InputType InputType;
+		public bool NeedValue => (InputType == InputType.IntValue || InputType == InputType.StrValue);
+		public bool OneInput = false;
+		public bool StopMesskip = false;
+		public bool IsSystemInput = false;
+
+		public bool HasDefValue = false;
+		public long DefIntValue;
+		public string DefStrValue;
+
+		public long Timelimit = -1;
+		public bool DisplayTime;
+		public string TimeUpMes;
+
+		static Int64 LastRequestID;
+	}
+}

+ 260 - 0
NTERA/Game/GameProc/LabelDictionary.cs

@@ -0,0 +1,260 @@
+using System.Collections.Generic;
+
+namespace MinorShift.Emuera.GameProc
+{
+	//1.713 LogicalLine.csから分割
+	/// <summary>
+	/// ラベルのジャンプ先の辞書。Erbファイル読み込み時に作成
+	/// </summary>
+	internal sealed class LabelDictionary
+	{
+		public LabelDictionary()
+		{
+			Initialized = false;
+		}
+		/// <summary>
+		/// 本体。全てのFunctionLabelLineを記録
+		/// </summary>
+		Dictionary<string, List<FunctionLabelLine>> labelAtDic = new Dictionary<string, List<FunctionLabelLine>>();
+		List<FunctionLabelLine> invalidList = new List<FunctionLabelLine>();
+		List<GotoLabelLine> labelDollarList = new List<GotoLabelLine>();
+		int count;
+
+		Dictionary<string, int> loadedFileDic = new Dictionary<string, int>();
+		int currentFileCount;
+		int totalFileCount;
+
+		public int Count => count;
+
+		/// <summary>
+		/// これがfalseである間は式中関数は呼べない
+		/// (つまり関数宣言の初期値として式中関数は使えない)
+		/// </summary>
+		public bool Initialized { get; set; }
+		#region Initialized 前用
+		public FunctionLabelLine GetSameNameLabel(FunctionLabelLine point)
+		{
+			string id = point.LabelName;
+			if (!labelAtDic.ContainsKey(id))
+				return null;
+			if (point.IsError)
+				return null;
+			List<FunctionLabelLine> labelList = labelAtDic[id];
+			if (labelList.Count <= 1)
+				return null;
+			return labelList[0];
+		}
+
+
+		Dictionary<string, List<FunctionLabelLine>[]> eventLabelDic = new Dictionary<string, List<FunctionLabelLine>[]>();
+		Dictionary<string, FunctionLabelLine> noneventLabelDic = new Dictionary<string, FunctionLabelLine>();
+
+		public void SortLabels()
+		{
+			foreach (KeyValuePair<string, List<FunctionLabelLine>[]> pair in eventLabelDic)
+				foreach (List<FunctionLabelLine> list in pair.Value)
+					list.Clear();
+			eventLabelDic.Clear();
+			noneventLabelDic.Clear();
+			foreach (KeyValuePair<string, List<FunctionLabelLine>> pair in labelAtDic)
+			{
+				string key = pair.Key;
+				List<FunctionLabelLine> list = pair.Value;
+				if(list.Count > 1)
+					list.Sort();
+				if (!list[0].IsEvent)
+				{
+					noneventLabelDic.Add(key, list[0]);
+                    GlobalStatic.IdentifierDictionary.resizeLocalVars("ARG", list[0].LabelName, list[0].ArgLength);
+                    GlobalStatic.IdentifierDictionary.resizeLocalVars("ARGS", list[0].LabelName, list[0].ArgsLength);
+					continue;
+				}
+				//1810alpha010 オプションによりイベント関数をイベント関数でないかのように呼び出すことを許可
+				//eramaker仕様 - #PRI #LATER #SINGLE等を無視し、最先に定義された関数1つのみを呼び出す
+				if (Config.CompatiCallEvent)
+					noneventLabelDic.Add(key, list[0]);
+				List<FunctionLabelLine>[] eventLabels = new List<FunctionLabelLine>[4];
+                List<FunctionLabelLine> onlylist = new List<FunctionLabelLine>();
+				List<FunctionLabelLine> prilist = new List<FunctionLabelLine>();
+				List<FunctionLabelLine> normallist = new List<FunctionLabelLine>();
+				List<FunctionLabelLine> laterlist = new List<FunctionLabelLine>();
+                int localMax = 0;
+                int localsMax = 0;
+				for (int i = 0; i < list.Count; i++)
+				{
+                    if (list[i].LocalLength > localMax)
+                        localMax = list[i].LocalLength;
+                    if (list[i].LocalsLength > localsMax)
+                        localsMax = list[i].LocalsLength;
+                    if (list[i].IsOnly)
+                        onlylist.Add(list[i]);
+					if (list[i].IsPri)
+						prilist.Add(list[i]);
+					if (list[i].IsLater)
+						laterlist.Add(list[i]);//#PRIかつ#LATERなら二重に登録する。eramakerの仕様
+					if ((!list[i].IsPri) && (!list[i].IsLater))
+						normallist.Add(list[i]);
+				}
+                if (localMax < GlobalStatic.IdentifierDictionary.getLocalDefaultSize("LOCAL"))
+                    localMax = GlobalStatic.IdentifierDictionary.getLocalDefaultSize("LOCAL");
+                if (localsMax < GlobalStatic.IdentifierDictionary.getLocalDefaultSize("LOCALS"))
+                    localsMax = GlobalStatic.IdentifierDictionary.getLocalDefaultSize("LOCALS");
+                eventLabels[0] = onlylist;
+				eventLabels[1] = prilist;
+				eventLabels[2] = normallist;
+				eventLabels[3] = laterlist;
+                for (int i = 0; i < 4; i++)
+                {
+                    for (int j = 0; j < eventLabels[i].Count; j++)
+                    {
+                        eventLabels[i][j].LocalLength = localMax;
+                        eventLabels[i][j].LocalsLength = localsMax;
+                    }
+                }
+                eventLabelDic.Add(key, eventLabels);
+			}
+		}
+
+		public void RemoveAll()
+		{
+			Initialized = false;
+			count = 0;
+			foreach (KeyValuePair<string, List<FunctionLabelLine>[]> pair in eventLabelDic)
+				foreach (List<FunctionLabelLine> list in pair.Value)
+					list.Clear();
+			eventLabelDic.Clear();
+			noneventLabelDic.Clear();
+
+			foreach (KeyValuePair<string, List<FunctionLabelLine>> pair in labelAtDic)
+				pair.Value.Clear();
+			labelAtDic.Clear();
+			labelDollarList.Clear();
+			loadedFileDic.Clear();
+			invalidList.Clear();
+			currentFileCount = 0;
+			totalFileCount = 0;
+		}
+
+		public void RemoveLabelWithPath(string fname)
+		{
+			List<FunctionLabelLine> labelLines;
+			List<FunctionLabelLine> removeLine = new List<FunctionLabelLine>();
+			List<string> removeKey = new List<string>();
+			foreach (KeyValuePair<string, List<FunctionLabelLine>> pair in labelAtDic)
+			{
+				string key = pair.Key;
+				labelLines = pair.Value;
+				foreach (FunctionLabelLine labelLine in labelLines)
+				{
+					if (string.Equals(labelLine.Position.Filename, fname, Config.SCIgnoreCase))
+						removeLine.Add(labelLine);
+				}
+				foreach (FunctionLabelLine remove in removeLine)
+				{
+					labelLines.Remove(remove);
+					if (labelLines.Count == 0)
+						removeKey.Add(key);
+				}
+				removeLine.Clear();
+			}
+			foreach (string rKey in removeKey)
+			{
+				labelAtDic.Remove(rKey);
+			}
+			for (int i = 0; i < invalidList.Count; i++)
+			{
+				if (string.Equals(invalidList[i].Position.Filename, fname, Config.SCIgnoreCase))
+				{
+					invalidList.RemoveAt(i);
+					i--;
+				}
+			}
+		}
+
+
+		public void AddFilename(string filename)
+		{
+			int curCount = 0;
+			if (loadedFileDic.TryGetValue(filename, out curCount))
+			{
+				currentFileCount = curCount;
+				RemoveLabelWithPath(filename);
+				return;
+			}
+			totalFileCount++;
+			currentFileCount = totalFileCount;
+			loadedFileDic.Add(filename, totalFileCount);
+		}
+		public void AddLabel(FunctionLabelLine point)
+		{
+			point.Index = count;
+			point.FileIndex = currentFileCount;
+			count++;
+			string id = point.LabelName;
+			if (labelAtDic.ContainsKey(id))
+			{
+				labelAtDic[id].Add(point);
+			}
+			else
+			{
+				List<FunctionLabelLine> labelList = new List<FunctionLabelLine>();
+				labelList.Add(point);
+				labelAtDic.Add(id, labelList);
+			}
+		}
+
+		public bool AddLabelDollar(GotoLabelLine point)
+		{
+			string id = point.LabelName;
+			foreach (GotoLabelLine label in labelDollarList)
+			{
+				if (label.LabelName == id && label.ParentLabelLine == point.ParentLabelLine)
+					return false;
+			}
+			labelDollarList.Add(point);
+			return true;
+		}
+
+		#endregion
+
+		
+		public List<FunctionLabelLine>[] GetEventLabels(string key)
+		{
+			List<FunctionLabelLine>[] ret = null;
+			eventLabelDic.TryGetValue(key, out ret);
+			return ret;
+		}
+
+		public FunctionLabelLine GetNonEventLabel(string key)
+		{
+			FunctionLabelLine ret = null;
+			noneventLabelDic.TryGetValue(key, out ret);
+			return ret;
+		}
+
+		public List<FunctionLabelLine> GetAllLabels(bool getInvalidList)
+		{
+			List<FunctionLabelLine> ret = new List<FunctionLabelLine>();
+			foreach (List<FunctionLabelLine> list in labelAtDic.Values)
+				ret.AddRange(list);
+			if(getInvalidList)
+				ret.AddRange(invalidList);
+			return ret;
+		}
+
+		public GotoLabelLine GetLabelDollar(string key, FunctionLabelLine labelAtLine)
+		{
+			foreach (GotoLabelLine label in labelDollarList)
+			{
+				if ((label.LabelName == key) && (label.ParentLabelLine == labelAtLine))
+					return label;
+			}
+			return null;
+		}
+		
+		internal void AddInvalidLabel(FunctionLabelLine invalidLabelLine)
+		{
+			invalidList.Add(invalidLabelLine);
+		}
+    }
+}

+ 343 - 0
NTERA/Game/GameProc/LogicalLine.cs

@@ -0,0 +1,343 @@
+using System;
+using System.Collections.Generic;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.GameProc.Function;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameProc
+{
+	/// <summary>
+	/// 命令文1行に相当する抽象クラス
+	/// </summary>
+	internal abstract class LogicalLine
+	{
+		protected ScriptPosition position;
+
+		//LogicalLine prevLine;
+		LogicalLine nextLine;
+		public ScriptPosition Position => position;
+
+		public FunctionLabelLine ParentLabelLine { get; set; }
+		public LogicalLine NextLine
+		{
+			get => nextLine;
+			set { nextLine = value; }
+		}
+		public override string ToString()
+		{
+			if (position == null)
+				return base.ToString();
+			return string.Format("{0}:{1}:{2}", position.Filename, position.LineNo, position.RowLine);
+		}
+
+		protected bool isError;
+		protected string errMes = "";
+
+		public virtual string ErrMes
+		{
+			get => errMes;
+			set { errMes = value; }
+		}
+		public virtual bool IsError
+		{
+			get => isError;
+			set { isError = value; }
+		}
+	}
+
+	///// <summary>
+	///// コメント行。
+	///// </summary>
+	//internal sealed class CommentLine : LogicalLine
+	//{
+	//    public CommentLine(ScriptPosition thePosition, string str)
+	//    {
+	//        base.position = thePosition;
+	//        //comment = str;
+	//    }
+	//    //string comment;
+	//    public override bool IsError
+	//    {
+	//        get { return false; }
+	//    }
+	//}
+
+	/// <summary>
+	/// 無効な行。
+	/// </summary>
+	internal sealed class InvalidLine : LogicalLine
+	{
+		public InvalidLine(ScriptPosition thePosition, string err)
+		{
+			position = thePosition;
+			errMes = err;
+		}
+		public override bool IsError => true;
+	}
+
+	/// <summary>
+	/// 命令文
+	/// </summary>
+	internal sealed class InstructionLine : LogicalLine
+	{
+		public InstructionLine(ScriptPosition thePosition, FunctionIdentifier theFunc, StringStream theArgPrimitive)
+		{
+			position = thePosition;
+			func = theFunc;
+			argprimitive = theArgPrimitive;
+		}
+
+		public InstructionLine(ScriptPosition thePosition, FunctionIdentifier functionIdentifier, OperatorCode assignOP, WordCollection dest, StringStream theArgPrimitive)
+		{
+			position = thePosition;
+			func = functionIdentifier;
+			AssignOperator = assignOP;
+			assigndest = dest;
+			argprimitive = theArgPrimitive;
+		}
+		readonly FunctionIdentifier func;
+		StringStream argprimitive;
+
+		WordCollection assigndest;
+		public OperatorCode AssignOperator { get; private set; }
+		Int64 subData;
+		public FunctionCode FunctionCode => func.Code;
+
+		public FunctionIdentifier Function => func;
+		public Argument Argument { get; set; }
+		public StringStream PopArgumentPrimitive()
+		{
+			StringStream ret = argprimitive;
+			argprimitive = null;
+			return ret;
+		}
+		public WordCollection PopAssignmentDestStr()
+		{
+			WordCollection ret = assigndest;
+			assigndest = null;
+			return ret;
+		}
+
+		/// <summary>
+		/// 繰り返しの終了を記憶する
+		/// </summary>
+		public Int64 LoopEnd
+		{
+			get => subData;
+			set { subData = value; }
+		}
+
+		VariableTerm cnt;
+		/// <summary>
+		/// 繰り返しにつかう変数を記憶する
+		/// </summary>
+		public VariableTerm LoopCounter
+		{
+			get => cnt;
+			set { cnt = value; }
+		}
+
+		Int64 step;
+		/// <summary>
+		/// 繰り返しのたびに増加する値を記憶する
+		/// </summary>
+		public Int64 LoopStep
+		{
+			get => step;
+			set { step = value; }
+		}
+
+		private LogicalLine jumpto;
+        private LogicalLine jumptoendcatch;
+		//IF文とSELECT文のみが使う。
+		public List<InstructionLine> IfCaseList = null;
+        //PRINTDATA文のみが使う。
+        public List<List<InstructionLine>> dataList = null;
+        //TRYCALLLIST系が使う
+        public List<InstructionLine> callList = null;
+
+		public LogicalLine JumpTo
+		{
+			get => jumpto;
+			set { jumpto = value; }
+		}
+
+        public LogicalLine JumpToEndCatch
+        {
+            get => jumptoendcatch;
+	        set { jumptoendcatch = value; }
+        }
+
+	}
+
+	/// <summary>
+	/// ファイルの始端と終端
+	/// </summary>
+	internal sealed class NullLine : LogicalLine { }
+	
+	/// <summary>
+	/// ラベルがエラーになっている関数行専用のクラス
+	/// </summary>
+	internal sealed class InvalidLabelLine : FunctionLabelLine
+	{
+		public InvalidLabelLine(ScriptPosition thePosition, string labelname, string err)
+		{
+			position = thePosition;
+		    LabelName = labelname != null ? String.Intern(labelname) : labelname;
+            errMes = err;
+			IsSingle = false;
+			Index = -1;
+			Depth = -1;
+			IsMethod = false;
+			MethodType = typeof(void);
+		}
+		public override bool IsError => true;
+	}
+
+	/// <summary>
+	/// @で始まるラベル行
+	/// </summary>
+	internal class FunctionLabelLine : LogicalLine, IComparable<FunctionLabelLine>
+	{
+		protected FunctionLabelLine() { }
+		public FunctionLabelLine(ScriptPosition thePosition, string labelname, WordCollection wc)
+		{
+			position = thePosition;
+		    LabelName = labelname != null ? String.Intern(labelname) : labelname;
+			IsSingle = false;
+			hasPrivDynamicVar = false;
+			Index = -1;
+			Depth = -1;
+			LocalLength = 0;
+			LocalsLength = 0;
+			ArgLength = 0;
+			ArgsLength = 0;
+			IsMethod = false;
+			MethodType = typeof(void);
+			this.wc = wc;
+
+			//ArgOptional = true;
+			//ArgAutoConvert = true;
+		}
+		WordCollection wc;
+		public WordCollection PopRowArgs()
+		{
+			WordCollection ret = wc;
+			wc = null;
+			return ret;
+		}
+
+		public string LabelName { get; protected set; }
+		public bool IsEvent { get; set; }
+		public bool IsSystem { get; set; }
+		public bool IsSingle { get; set; }
+		public bool IsPri { get; set; }
+		public bool IsLater { get; set; }
+		public bool IsOnly { get; set; }
+		public bool hasPrivDynamicVar { get; set; }
+		public int LocalLength { get; set; }
+		public int LocalsLength { get; set; }
+		public int ArgLength { get; set; }
+		public int ArgsLength { get; set; }
+
+		//public bool ArgOptional { get; set; }
+		//public bool ArgAutoConvert { get; set; }
+
+		public bool IsMethod { get; set; }
+		public Type MethodType { get; set; }
+		public VariableTerm[] Arg { get; set; }
+		public SingleTerm[] Def { get; set; }
+        //public SingleTerm[] SubNames { get; set; }
+		public int Depth { get; set; }
+
+		#region IComparable<FunctionLabelLine> メンバ
+		//ソート用情報
+		public int Index { get; set; }
+		public int FileIndex { get; set; }
+		public int CompareTo(FunctionLabelLine other)
+		{
+			if (FileIndex != other.FileIndex)
+				return FileIndex.CompareTo(other.FileIndex);
+			//position == nullであるLine(デバッグコマンドなど)をSortすることはないはず
+			if (position.LineNo != other.position.LineNo)
+				return position.LineNo.CompareTo(other.position.LineNo);
+			return Index.CompareTo(other.Index);
+		}
+		#endregion
+		#region private変数
+		Dictionary<string, UserDefinedVariableToken> privateVar = new Dictionary<string, UserDefinedVariableToken>();
+		internal bool AddPrivateVariable(UserDefinedVariableData data)
+		{
+			if (privateVar.ContainsKey(data.Name))
+				return false;
+			UserDefinedVariableToken var = GlobalStatic.VariableData.CreatePrivateVariable(data);
+			privateVar.Add(data.Name, var);
+			//静的な変数のみの場合は関数呼び出し時に何もする必要がない
+			if (!data.Static)
+				hasPrivDynamicVar = true;
+			return true;
+		}
+		internal UserDefinedVariableToken GetPrivateVariable(string key)
+		{
+			UserDefinedVariableToken var = null;
+			privateVar.TryGetValue(key, out var);
+			return var;
+		}
+
+		/// <summary>
+		/// 引数の値の確定後、引数の代入より前に呼ぶこと
+		/// </summary>
+		internal void In()
+		{
+#if DEBUG
+			GlobalStatic.StackList.Add(this);
+#endif
+			foreach (UserDefinedVariableToken var in privateVar.Values)
+				if (!var.IsStatic)
+					var.In();
+		}
+		internal void Out()
+		{
+#if DEBUG
+			GlobalStatic.StackList.Remove(this);
+#endif
+			foreach (UserDefinedVariableToken var in privateVar.Values)
+				if (!var.IsStatic)
+					var.Out();
+		}
+		#endregion
+
+	}
+
+	/// <summary>
+	/// $で始まるラベル行
+	/// </summary>
+	internal sealed class GotoLabelLine : LogicalLine, IEqualityComparer<GotoLabelLine>
+	{
+		public GotoLabelLine(ScriptPosition thePosition, string labelname)
+		{
+			position = thePosition;
+			this.labelname = String.Intern(labelname);
+		}
+		readonly string labelname = "";
+		public string LabelName => labelname;
+
+	    #region IEqualityComparer<GotoLabelLine> メンバ
+
+		public bool Equals(GotoLabelLine x, GotoLabelLine y)
+		{
+			if ((x == null) || (y == null))
+				return false;
+			return ((x.ParentLabelLine == y.ParentLabelLine) && (x.labelname == y.labelname));
+		}
+
+		public int GetHashCode(GotoLabelLine obj)
+		{
+			return labelname.GetHashCode() ^ ParentLabelLine.GetHashCode();
+		}
+
+		#endregion
+	}
+
+}

+ 488 - 0
NTERA/Game/GameProc/LogicalLineParser.cs

@@ -0,0 +1,488 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Media;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.GameProc.Function;
+using MinorShift.Emuera.Sub;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera.GameProc
+{
+	internal static class LogicalLineParser
+	{
+		public static bool ParseSharpLine(FunctionLabelLine label, StringStream st, ScriptPosition position, List<string> OnlyLabel)
+		{
+			st.ShiftNext();//'#'を飛ばす
+			string token = LexicalAnalyzer.ReadSingleIdentifier(st);//#~自体にはマクロ非適用
+			if (Config.ICFunction)
+				token = token.ToUpper();
+            //#行として不正な行でもAnalyzeに行って引っかかることがあるので、先に存在しない#~は弾いてしまう
+            if (token == null || (token != "SINGLE" && token != "LATER" && token != "PRI" && token != "ONLY" && token != "FUNCTION" && token != "FUNCTIONS" 
+                && token != "LOCALSIZE" && token != "LOCALSSIZE" && token != "DIM" && token != "DIMS"))
+            {
+                ParserMediator.Warn("解釈できない#行です", position, 1);
+                return false;
+            }
+			try
+			{
+				WordCollection wc = LexicalAnalyzer.Analyse(st, LexEndWith.EoL, LexAnalyzeFlag.AllowAssignment);
+				switch (token)
+				{
+					case "SINGLE":
+						if (label.IsMethod)
+						{
+							ParserMediator.Warn("式中関数では#SINGLEは機能しません", position, 1);
+							break;
+						}
+						else if (!label.IsEvent)
+						{
+							ParserMediator.Warn("イベント関数以外では#SINGLEは機能しません", position, 1);
+							break;
+						}
+						else if (label.IsSingle)
+						{
+							ParserMediator.Warn("#SINGLEが重複して使われています", position, 1);
+							break;
+						}
+						else if (label.IsOnly)
+						{
+							ParserMediator.Warn("#ONLYが指定されたイベント関数では#SINGLEは機能しません", position, 1);
+							break;
+						}
+						label.IsSingle = true;
+						break;
+					case "LATER":
+						if (label.IsMethod)
+						{
+							ParserMediator.Warn("式中関数では#LATERは機能しません", position, 1);
+							break;
+						}
+						else if (!label.IsEvent)
+						{
+							ParserMediator.Warn("イベント関数以外では#LATERは機能しません", position, 1);
+							break;
+						}
+						else if (label.IsLater)
+						{
+							ParserMediator.Warn("#LATERが重複して使われています", position, 1);
+							break;
+						}
+						else if (label.IsOnly)
+						{
+							ParserMediator.Warn("#ONLYが指定されたイベント関数では#LATERは機能しません", position, 1);
+							break;
+						}
+						else if (label.IsPri)
+							ParserMediator.Warn("#PRIと#LATERが重複して使われています(この関数は2度呼ばれます)", position, 1);
+						label.IsLater = true;
+						break;
+					case "PRI":
+						if (label.IsMethod)
+						{
+							ParserMediator.Warn("式中関数では#PRIは機能しません", position, 1);
+							break;
+						}
+						else if (!label.IsEvent)
+						{
+							ParserMediator.Warn("イベント関数以外では#PRIは機能しません", position, 1);
+							break;
+						}
+						else if (label.IsPri)
+						{
+							ParserMediator.Warn("#PRIが重複して使われています", position, 1);
+							break;
+						}
+						else if (label.IsOnly)
+						{
+							ParserMediator.Warn("#ONLYが指定されたイベント関数では#PRIは機能しません", position, 1);
+							break;
+						}
+						else if (label.IsLater)
+							ParserMediator.Warn("#PRIと#LATERが重複して使われています(この関数は2度呼ばれます)", position, 1);
+						label.IsPri = true;
+						break;
+					case "ONLY":
+						if (label.IsMethod)
+						{
+							ParserMediator.Warn("式中関数では#ONLYは機能しません", position, 1);
+							break;
+						}
+						else if (!label.IsEvent)
+						{
+							ParserMediator.Warn("イベント関数以外では#ONLYは機能しません", position, 1);
+							break;
+						}
+						else if (label.IsOnly)
+						{
+							ParserMediator.Warn("#ONLYが重複して使われています", position, 1);
+							break;
+						}
+						else if (OnlyLabel.Contains(label.LabelName))
+							ParserMediator.Warn("このイベント関数\"@" + label.LabelName + "\"にはすでに#ONLYが宣言されています(この関数は実行されません)", position, 1);
+						OnlyLabel.Add(label.LabelName);
+						label.IsOnly = true;
+						if (label.IsPri)
+						{
+							ParserMediator.Warn("このイベント関数には#PRIが宣言されていますが無視されます", position, 1);
+							label.IsPri = false;
+						}
+						if (label.IsLater)
+						{
+							ParserMediator.Warn("このイベント関数には#LATERが宣言されていますが無視されます", position, 1);
+							label.IsLater = false;
+						}
+						if (label.IsSingle)
+						{
+							ParserMediator.Warn("このイベント関数には#SINGLEが宣言されていますが無視されます", position, 1);
+							label.IsSingle = false;
+						}
+						break;
+					case "FUNCTION":
+					case "FUNCTIONS":
+						if (!string.IsNullOrEmpty(label.LabelName) && char.IsDigit(label.LabelName[0]))
+						{
+							ParserMediator.Warn("#" + token + "属性は関数名が数字で始まる関数には指定できません", position, 1);
+							label.IsError = true;
+							label.ErrMes = "関数名が数字で始まっています";
+							break;
+						}
+						if (label.IsMethod)
+						{
+							if ((label.MethodType == typeof(Int64) && token == "FUNCTION") || (label.MethodType == typeof(string) && token == "FUNCTIONS"))
+							{
+								ParserMediator.Warn("関数" + label.LabelName + "にはすでに#" + token + "が宣言されています(この行は無視されます)", position, 1);
+								return false;
+							}
+							if (label.MethodType == typeof(Int64) && token == "FUNCTIONS")
+								ParserMediator.Warn("関数" + label.LabelName + "にはすでに#FUNCTIONが宣言されています", position, 2);
+							else if (label.MethodType == typeof(string) && token == "FUNCTION")
+								ParserMediator.Warn("関数" + label.LabelName + "にはすでに#FUNCTIONSが宣言されています", position, 2);
+							return false;
+						}
+						if (label.Depth == 0)
+						{
+							ParserMediator.Warn("システム関数に#" + token + "が指定されています", position, 2);
+							return false;
+						}
+						label.IsMethod = true;
+						label.Depth = 0;
+						if (token == "FUNCTIONS")
+							label.MethodType = typeof(string);
+						else
+							label.MethodType = typeof(Int64);
+						if (label.IsPri)
+						{
+							ParserMediator.Warn("式中関数では#PRIは機能しません", position, 1);
+							label.IsPri = false;
+						}
+						if (label.IsLater)
+						{
+							ParserMediator.Warn("式中関数では#LATERは機能しません", position, 1);
+							label.IsLater = false;
+						}
+						if (label.IsSingle)
+						{
+							ParserMediator.Warn("式中関数では#SINGLEは機能しません", position, 1);
+							label.IsSingle = false;
+						}
+						if (label.IsOnly)
+						{
+							ParserMediator.Warn("式中関数では#ONLYは機能しません", position, 1);
+							label.IsOnly = false;
+						}
+						break;
+					case "LOCALSIZE":
+					case "LOCALSSIZE":
+						{
+							if (wc.EOL)
+							{
+								ParserMediator.Warn("#" + token + "の後に有効な数値が指定されていません", position, 2);
+								break;
+							}
+                            //イベント関数では指定しても無視される
+                            if (label.IsEvent)
+                            {
+                                ParserMediator.Warn("イベント関数では#" + token + "による" + token.Substring(0, token.Length - 4)+ "のサイズ指定は無視されます", position, 1);
+                                break;
+                            }
+							IOperandTerm arg = ExpressionParser.ReduceIntegerTerm(wc, TermEndWith.EoL);
+							SingleTerm sizeTerm = arg.Restructure(null) as SingleTerm;
+							if ((sizeTerm == null) || (sizeTerm.GetOperandType() != typeof(Int64)))
+							{
+								ParserMediator.Warn("#" + token + "の後に有効な定数式が指定されていません", position, 2);
+								break;
+							}
+							if (sizeTerm.Int <= 0)
+							{
+								ParserMediator.Warn("#" + token + "に0以下の値(" + sizeTerm.Int + ")が与えられました。設定は無視されます", position, 1);
+								break;
+							}
+							if (sizeTerm.Int >= Int32.MaxValue)
+							{
+								ParserMediator.Warn("#" + token + "に大きすぎる値(" + sizeTerm.Int + ")が与えられました。設定は無視されます", position, 1);
+								break;
+							}
+							int size = (int)sizeTerm.Int;
+							if (token == "LOCALSIZE")
+							{
+								if (GlobalStatic.IdentifierDictionary.getLocalIsForbid("LOCAL"))
+								{
+									ParserMediator.Warn("#" + token + "が指定されていますが変数LOCALは使用禁止されています", position, 2);
+									break;
+								}
+								if (label.LocalLength > 0)
+									ParserMediator.Warn("この関数にはすでに#LOCALSIZEが定義されています。(以前の定義は無視されます)", position, 1);
+								label.LocalLength = size;
+							}
+							else
+							{
+								if (GlobalStatic.IdentifierDictionary.getLocalIsForbid("LOCALS"))
+								{
+									ParserMediator.Warn("#" + token + "が指定されていますが変数LOCALSは使用禁止されています", position, 2);
+									break;
+								}
+								if (label.LocalsLength > 0)
+									ParserMediator.Warn("この関数にはすでに#LOCALSSIZEが定義されています。(以前の定義は無視されます)", position, 1);
+								label.LocalsLength = size;
+							}
+						}
+						break;
+					case "DIM":
+					case "DIMS":
+						{
+							UserDefinedVariableData data = UserDefinedVariableData.Create(wc, token == "DIMS", true, position);
+							if (!label.AddPrivateVariable(data))
+							{
+								ParserMediator.Warn("変数名" + data.Name + "は既に使用されています", position, 2);
+								return false;
+							}
+							break;
+						}
+					default:
+						ParserMediator.Warn("解釈できない#行です", position, 1);
+						break;
+				}
+				if (!wc.EOL)
+					ParserMediator.Warn("#の識別子の後に余分な文字があります", position, 1);
+			}
+			catch (Exception e)
+			{
+				ParserMediator.Warn(e.Message, position, 2);
+				goto err;
+			}
+			return true;
+		err:
+			return false;
+		}
+		
+		public static LogicalLine ParseLine(string str, IConsole console)
+		{
+			ScriptPosition position = new ScriptPosition(str);
+			StringStream stream = new StringStream(str);
+			return ParseLine(stream, position, console);
+		}
+
+		public static LogicalLine ParseLabelLine(StringStream stream, ScriptPosition position, IConsole console)
+		{
+			bool isFunction = (stream.Current == '@');
+			int lineNo = position.LineNo;
+			string labelName = "";
+			string errMes = "";
+			try
+			{
+				int warnLevel = -1;
+                stream.ShiftNext();//@か$を除去
+				WordCollection wc = LexicalAnalyzer.Analyse(stream, LexEndWith.EoL, LexAnalyzeFlag.AllowAssignment);
+				if (wc.EOL || !(wc.Current is IdentifierWord))
+				{
+					errMes = "関数名が不正であるか存在しません";
+					goto err;
+				}
+				labelName = ((IdentifierWord)wc.Current).Code;
+				wc.ShiftNext();
+				if (Config.ICVariable)
+					labelName = labelName.ToUpper();
+				GlobalStatic.IdentifierDictionary.CheckUserLabelName(ref errMes, ref warnLevel, isFunction, labelName);
+				if (warnLevel >= 0)
+				{
+					if (warnLevel >= 2)
+						goto err;
+					ParserMediator.Warn(errMes, position, warnLevel);
+				}
+				if (!isFunction)//$ならこの時点で終了
+				{
+					if (!wc.EOL)
+						ParserMediator.Warn("$で始まるラベルに引数が設定されています", position, 1);
+					return new GotoLabelLine(position, labelName);
+				}
+
+
+
+				//labelName = LexicalAnalyzer.ReadString(stream, StrEndWith.LeftParenthesis_Bracket_Comma_Semicolon);
+				//labelName = labelName.Trim();
+				//if (Config.ICVariable)
+				//    labelName = labelName.ToUpper();
+				//GlobalStatic.IdentifierDictionary.CheckUserLabelName(ref errMes, ref warnLevel, isFunction, labelName);
+				//if(warnLevel >= 0)
+				//{
+				//    if (warnLevel >= 2)
+				//        goto err;
+				//    ParserMediator.Warn(errMes, position, warnLevel);
+				//}
+				//if (!isFunction)//$ならこの時点で終了
+				//{
+				//    LexicalAnalyzer.SkipWhiteSpace(stream);
+				//    if (!stream.EOS)
+				//        ParserMediator.Warn("$で始まるラベルに引数が設定されています", position, 1);
+				//    return new GotoLabelLine(position, labelName);
+				//}
+
+				////関数名部分に_renameを使えないように変更
+				//if (ParserMediator.RenameDic != null && ((stream.ToString().IndexOf("[[") >= 0) && (stream.ToString().IndexOf("]]") >= 0)))
+				//{
+				//    string line = stream.ToString();
+				//    foreach (KeyValuePair<string, string> pair in ParserMediator.RenameDic)
+				//        line = line.Replace(pair.Key, pair.Value);
+				//    stream = new StringStream(line);
+				//}
+				//WordCollection wc = null;
+				//wc = LexicalAnalyzer.Analyse(stream, LexEndWith.EoL, LexAnalyzeFlag.AllowAssignment);
+				if (Program.AnalysisMode)
+					console.PrintC("@" + labelName, false);
+				FunctionLabelLine funclabelLine = new FunctionLabelLine(position, labelName, wc);
+				if (IdentifierDictionary.IsEventLabelName(labelName))
+				{
+					funclabelLine.IsEvent = true;
+					funclabelLine.IsSystem = true;
+					funclabelLine.Depth = 0;
+				}
+				else if (IdentifierDictionary.IsSystemLabelName(labelName))
+				{
+					funclabelLine.IsSystem = true;
+					funclabelLine.Depth = 0;
+				}
+				return funclabelLine;
+			}
+			catch (CodeEE e)
+			{
+				errMes = e.Message;
+			}
+		err:
+			SystemSounds.Hand.Play();
+			if (isFunction)
+			{
+				if(labelName.Length == 0)
+					labelName = "<Error>";
+				return new InvalidLabelLine(position, labelName, errMes);
+			}
+			return new InvalidLine(position, errMes);
+		}
+		
+		
+		public static LogicalLine ParseLine(StringStream stream, ScriptPosition position, IConsole console)
+		{
+			int lineNo = position.LineNo;
+			string errMes = "";
+			LexicalAnalyzer.SkipWhiteSpace(stream);//先頭のホワイトスペースを読み飛ばす
+			if (stream.EOS)
+				return null;
+			//コメント行かどうかはここに来る前に判定しておく
+			try
+			{
+				#region 前置インクリメント、デクリメント行
+				if (stream.Current == '+' || stream.Current == '-')
+				{
+					char op = stream.Current;
+					WordCollection wc = LexicalAnalyzer.Analyse(stream, LexEndWith.EoL, LexAnalyzeFlag.None);
+					OperatorWord opWT = wc.Current as OperatorWord;
+					if ((opWT == null)|| ((opWT.Code != OperatorCode.Increment) &&(opWT.Code != OperatorCode.Decrement)) )
+					{
+						if (op == '+')
+							errMes = "行が\'+\'から始まっていますが、インクリメントではありません"; 
+						else
+							errMes = "行が\'-\'から始まっていますが、デクリメントではありません";
+						goto err;
+					}
+					wc.ShiftNext();
+					//token = EpressionParser.単語一個分取得(wc)
+					//token非変数
+					//token文字列形
+					//token変更不可能
+					//if (wc != EOS)
+					//
+					return new InstructionLine(position, FunctionIdentifier.SETFunction, opWT.Code, wc, null);
+				}
+				#endregion
+				IdentifierWord idWT = LexicalAnalyzer.ReadFirstIdentifierWord(stream);
+				if (idWT != null)
+				{
+					FunctionIdentifier func = GlobalStatic.IdentifierDictionary.GetFunctionIdentifier(idWT.Code);
+					//命令文
+					if (func != null)//関数文
+					{
+						if (stream.EOS) //引数の無い関数
+							return new InstructionLine(position, func, stream);
+						if ((stream.Current != ';') && (stream.Current != ' ') && (stream.Current != '\t') && (!Config.SystemAllowFullSpace || (stream.Current != ' ')))
+						{
+							if (stream.Current == ' ')
+								errMes = "命令で行が始まっていますが、命令の直後に半角スペース・タブ以外の文字が来ています(この警告はシステムオプション「" + Config.GetConfigName(ConfigCode.SystemAllowFullSpace) + "」により無視できます)";
+							else
+								errMes = "命令で行が始まっていますが、命令の直後に半角スペース・タブ以外の文字が来ています";
+							goto err;
+						}
+						stream.ShiftNext();
+						return new InstructionLine(position, func, stream);
+					}
+				}
+				LexicalAnalyzer.SkipWhiteSpace(stream);
+				if (stream.EOS)
+				{
+					errMes = "解釈できない行です";
+					goto err;
+				}
+				//命令行ではない→代入行のはず
+				stream.Seek(0, SeekOrigin.Begin);
+				OperatorCode assignOP = OperatorCode.NULL;
+				WordCollection wc1 = LexicalAnalyzer.Analyse(stream, LexEndWith.Operator, LexAnalyzeFlag.None);
+				//if (idWT != null)
+				//	wc1.Collection.Insert(0, idWT);
+				try
+				{
+					assignOP = LexicalAnalyzer.ReadAssignmentOperator(stream);
+				}
+				catch(CodeEE)
+				{
+					errMes = "解釈できない行です";
+					goto err;
+				}
+				//eramaker互換警告
+				//stream.Jump(-1);
+				//if ((stream.Current != ' ') && (stream.Current != '\t'))
+				//{
+				//	errMes = "変数で行が始まっていますが、演算子の直前に半角スペースまたはタブがありません";
+				//	goto err;
+				//}
+				//stream.ShiftNext();
+
+
+				if (assignOP == OperatorCode.Equal)
+				{
+					if (console != null)
+						ParserMediator.Warn("代入演算子に\"==\"が使われています", position, 0);
+					//"=="を代入文に使うのは本当はおかしいが結構使われているので仕様にする
+					assignOP = OperatorCode.Assignment;
+				}
+				return new InstructionLine(position, FunctionIdentifier.SETFunction, assignOP, wc1, stream);
+			err:
+				return new InvalidLine(position, errMes);
+			}
+			catch (CodeEE e)
+			{
+				SystemSounds.Hand.Play();
+				return new InvalidLine(position, e.Message);
+			}
+		}
+		
+	}
+}

+ 312 - 0
NTERA/Game/GameProc/Process.CalledFunction.cs

@@ -0,0 +1,312 @@
+using System;
+using System.Collections.Generic;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.GameData.Function;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameProc
+{
+
+	internal sealed class UserDefinedFunctionArgument
+	{
+		public UserDefinedFunctionArgument(IOperandTerm[] srcArgs, VariableTerm[] destArgs)
+		{
+			Arguments = srcArgs;
+			TransporterInt = new Int64[Arguments.Length];
+			TransporterStr = new string[Arguments.Length];
+			TransporterRef = new Array[Arguments.Length];
+			isRef = new bool[Arguments.Length];
+			for (int i = 0; i < Arguments.Length; i++)
+			{
+				isRef[i] = destArgs[i].Identifier.IsReference;
+			}
+		}
+		public readonly IOperandTerm[] Arguments;
+		public readonly Int64[] TransporterInt;
+		public readonly string[] TransporterStr;
+		public readonly Array[] TransporterRef;
+		public readonly bool[] isRef;
+		public void SetTransporter(ExpressionMediator exm)
+		{
+			for (int i = 0; i < Arguments.Length; i++)
+			{
+				if (Arguments[i] == null)
+					continue;
+				if (isRef[i])
+				{
+					VariableTerm vTerm = (VariableTerm)Arguments[i];
+					if (vTerm.Identifier.IsCharacterData)
+					{
+						Int64 charaNo = vTerm.GetElementInt(0, exm);
+						if ((charaNo < 0) || (charaNo >= GlobalStatic.VariableData.CharacterList.Count))
+							throw new CodeEE("Character array variable " + vTerm.Identifier.Name + " at the first argument (" + charaNo + ") is out of range of the character registration number");
+						TransporterRef[i] = (Array)vTerm.Identifier.GetArrayChara((int)charaNo);
+					}
+					else
+						TransporterRef[i] = (Array)vTerm.Identifier.GetArray();
+
+				}
+				else if (Arguments[i].GetOperandType() == typeof(Int64))
+					TransporterInt[i] = Arguments[i].GetIntValue(exm);
+				else
+					TransporterStr[i] = Arguments[i].GetStrValue(exm);
+			}
+		}
+		public UserDefinedFunctionArgument Restructure(ExpressionMediator exm, bool tryTranslate=false)
+		{
+			for (int i = 0; i < Arguments.Length; i++)
+			{
+				if (Arguments[i] == null)
+					continue;
+				if(isRef[i])
+					Arguments[i].Restructure(exm);
+				else
+					Arguments[i] = Arguments[i].Restructure(exm);
+			}
+			return this;
+		}
+	}
+
+	/// <summary>
+	/// 現在呼び出し中の関数
+	/// イベント関数を除いて実行中に内部状態は変化しないので使いまわしても良い
+	/// </summary>
+	internal sealed class CalledFunction
+	{
+		private CalledFunction(string label) { FunctionName = label; }
+		public static CalledFunction CallEventFunction(Process parent, string label, LogicalLine retAddress)
+		{
+			CalledFunction called = new CalledFunction(label);
+			List<FunctionLabelLine> newLabelList = new List<FunctionLabelLine>();
+			called.Finished = false;
+			called.eventLabelList = parent.LabelDictionary.GetEventLabels(label);
+			if (called.eventLabelList == null)
+			{
+				FunctionLabelLine line = parent.LabelDictionary.GetNonEventLabel(label);
+				if (parent.LabelDictionary.GetNonEventLabel(label) != null)
+				{
+					throw new CodeEE("イベント関数でない関数@" + label + "(" + line.Position.Filename + ":" + line.Position.LineNo + "行目)に対しEVENT呼び出しが行われました");
+				}
+				return null;
+			}
+			called.counter = -1;
+			called.group = 0;
+			called.ShiftNext();
+			called.TopLabel = called.CurrentLabel;
+			called.returnAddress = retAddress;
+			called.IsEvent = true;
+			return called;
+		}
+
+		public static CalledFunction CallFunction(Process parent, string label, LogicalLine retAddress)
+		{
+			CalledFunction called = new CalledFunction(label);
+			called.Finished = false;
+			FunctionLabelLine labelline = parent.LabelDictionary.GetNonEventLabel(label);
+			if (labelline == null)
+			{
+				if (parent.LabelDictionary.GetEventLabels(label) != null)
+				{
+					throw new CodeEE("イベント関数@" + label + "に対し通常のCALLが行われました(このエラーは互換性オプション「" + Config.GetConfigName(ConfigCode.CompatiCallEvent) + "」により無視できます)");
+				}
+				return null;
+			}
+
+			if (labelline.IsMethod)
+			{
+				throw new CodeEE("#FUCNTION(S)が定義された関数@" + labelline.LabelName + "(" + labelline.Position.Filename + ":" + labelline.Position.LineNo + "行目)に対し通常のCALLが行われました");
+			}
+			called.TopLabel = labelline;
+			called.CurrentLabel = labelline;
+			called.returnAddress = retAddress;
+			called.IsEvent = false;
+            return called;
+		}
+
+		public static CalledFunction CreateCalledFunctionMethod(FunctionLabelLine labelline, string label)
+		{
+			CalledFunction called = new CalledFunction(label);
+			called.TopLabel = labelline;
+			called.CurrentLabel = labelline;
+			called.returnAddress = null;
+			called.IsEvent = false;
+			return called;
+		}
+		
+		
+		static FunctionMethod tostrMethod;
+		/// <summary>
+		/// 1803beta005 予め引数の数を合わせて規定値を代入しておく
+        /// 1806+v6.99 式中関数の引数に無効な#DIM変数を与えている場合に例外になるのを修正
+		/// 1808beta009 REF型に対応
+		/// </summary>
+		public UserDefinedFunctionArgument ConvertArg(IOperandTerm[] srcArgs, out string errMes)
+		{
+			errMes = null;
+            if (TopLabel.IsError)
+            {
+                errMes = TopLabel.ErrMes;
+                return null;
+            }
+            FunctionLabelLine func = TopLabel;
+            IOperandTerm[] convertedArg = new IOperandTerm[func.Arg.Length];
+			if(convertedArg.Length < srcArgs.Length)
+			{
+				errMes = "引数の数が関数\"@" + func.LabelName + "\"に設定された数を超えています";
+				return null;
+			}
+			IOperandTerm term = null;
+			VariableTerm destArg = null;
+			bool isString = false;
+			for (int i = 0; i < func.Arg.Length; i++)
+			{
+				term = (i < srcArgs.Length) ? srcArgs[i] : null;
+				destArg = func.Arg[i];
+				isString = destArg.IsString;
+				if (destArg.Identifier.IsReference)//参照渡しの場合
+				{
+					if (term == null)
+					{
+						errMes = "\"@" + func.LabelName + "\"の" + (i + 1) + "番目の引数は参照渡しのため省略できません";
+						return null;
+					}
+					VariableTerm vTerm = term as VariableTerm;
+					if (vTerm == null || vTerm.Identifier.Dimension == 0)
+					{
+						errMes = "\"@" + func.LabelName + "\"の" + (i + 1) + "番目の引数は参照渡しのための配列変数でなければなりません";
+						return null;
+					}
+					//TODO 1810alpha007 キャラ型を認めるかどうかはっきりしたい 今のところ認めない方向
+					//型チェック
+					if (!((ReferenceToken)destArg.Identifier).MatchType(vTerm.Identifier, false, out errMes))
+					{
+						errMes = "\"@" + func.LabelName + "\"の" + (i + 1) + "番目の引数:" + errMes;
+						return null;
+					}
+				}
+				else if (term == null)//引数が省略されたとき
+				{
+					term = func.Def[i];//デフォルト値を代入
+					//1808beta001 デフォルト値がない場合はエラーにする
+					//一応逃がす
+					if (term == null && !Config.CompatiFuncArgOptional)
+					{
+						errMes = "\"@" + func.LabelName + "\"の" + (i + 1) + "番目の引数は省略できません(この警告は互換性オプション「" + Config.GetConfigName(ConfigCode.CompatiFuncArgOptional) + "」により無視できます)";
+						return null;
+					}
+				}
+				else if (term.GetOperandType() != destArg.GetOperandType())
+				{
+					if (term.GetOperandType() == typeof(string))
+					{
+						errMes = "\"@" + func.LabelName + "\"の" + (i + 1) + "番目の引数を文字列型から整数型に変換できません";
+						return null;
+					}
+
+					if (!Config.CompatiFuncArgAutoConvert)
+					{
+						errMes = "\"@" + func.LabelName + "\"の" + (i + 1) + "番目の引数を整数型から文字列型に変換できません(この警告は互換性オプション「" + Config.GetConfigName(ConfigCode.CompatiFuncArgAutoConvert) + "」により無視できます)";
+						return null;
+					}
+					if (tostrMethod == null)
+						tostrMethod = FunctionMethodCreator.GetMethodList()["TOSTR"];
+					term = new FunctionMethodTerm(tostrMethod, new[] { term });
+				}
+				convertedArg[i] = term;
+			}
+			return new UserDefinedFunctionArgument(convertedArg, func.Arg);
+		}
+
+		public LogicalLine CallLabel(Process parent, string label)
+		{
+			return parent.LabelDictionary.GetLabelDollar(label, CurrentLabel);
+		}
+
+        public void updateRetAddress(LogicalLine line)
+        {
+            returnAddress = line;
+        }
+
+		public CalledFunction Clone()
+		{
+			CalledFunction called = new CalledFunction(FunctionName);
+			called.eventLabelList = eventLabelList;
+			called.CurrentLabel = CurrentLabel;
+			called.TopLabel = TopLabel;
+			called.group = group;
+			called.IsEvent = IsEvent;
+
+			called.counter = counter;
+			called.returnAddress = returnAddress;
+			return called;
+		}
+
+		List<FunctionLabelLine>[] eventLabelList;
+		public FunctionLabelLine CurrentLabel { get; private set; }
+		public FunctionLabelLine TopLabel { get; private set; }
+		int counter = -1;
+		int group;
+		LogicalLine returnAddress;
+		public readonly string FunctionName = "";
+		public bool IsJump { get; set; }
+		public bool Finished { get; private set; }
+		public LogicalLine ReturnAddress => returnAddress;
+		public bool IsEvent{get; private set;}
+
+		public bool HasSingleFlag
+		{
+			get
+			{
+				if (CurrentLabel == null)
+					return false;
+				return CurrentLabel.IsSingle;
+			}
+		}
+
+
+		#region イベント関数専用
+		public void ShiftNext()
+		{
+			while (true)
+			{
+				counter++;
+				if (eventLabelList[group].Count > counter)
+				{
+					CurrentLabel = (eventLabelList[group])[counter];
+					return;
+				}
+				group++;
+				counter = -1;
+				if (group >= 4)
+				{
+					CurrentLabel = null;
+					return;
+				}
+			}
+		}
+
+		public void ShiftNextGroup()
+		{
+			counter = -1;
+			group++;
+            if (group >= 4)
+            {
+                CurrentLabel = null;
+                return;
+            }
+			ShiftNext();
+		}
+
+        public void FinishEvent()
+        {
+            group = 4;
+            counter = -1;
+            CurrentLabel = null;
+        }
+
+        public bool IsOnly => CurrentLabel.IsOnly;
+
+		#endregion
+	}
+}

+ 946 - 0
NTERA/Game/GameProc/Process.ScriptProc.cs

@@ -0,0 +1,946 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.GameProc.Function;
+using MinorShift.Emuera.Sub;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera.GameProc
+{
+	internal sealed partial class Process
+	{
+		private void runScriptProc(bool translate = false)
+		{
+			while (true)
+			{
+				//bool sequential = state.Sequential;
+				state.ShiftNextLine();
+				//WinmmTimerから時間を取得するのはそれ自体結構なコストがかかるので10000行に一回くらいで。
+				if (Config.InfiniteLoopAlertTime > 0 && (state.lineCount % 10000 == 0))
+					checkInfiniteLoop();
+				LogicalLine line = state.CurrentLine;
+				InstructionLine func = line as InstructionLine;
+				//これがNULLになる様な処理は現状ないはず
+				//if (line == null)
+				//	throw new ExeEE("Emuera.exeは次に実行する行を見失いました");
+				if (line.IsError)
+					throw new CodeEE(line.ErrMes);
+				if (func != null)
+				{//1753 InstructionLineを先に持ってきてみる。わずかに速くなった気がしないでもない
+					if (!Program.DebugMode && func.Function.IsDebug())
+					{//非DebugモードでのDebug系命令。何もしない。(SIF文のためにコメント行扱いにはできない)
+						continue;
+					}
+					if (func.Argument == null)
+					{
+						ArgumentParser.SetArgumentTo(func);
+						if (func.IsError)
+							throw new CodeEE(func.ErrMes);
+					}
+					if ((skipPrint) && (func.Function.IsPrint()))
+					{
+						if ((userDefinedSkip) && (func.Function.IsInput()))
+						{
+							console.PrintError("表示スキップ中にデフォルト値を持たないINPUTに遭遇しました");
+							console.PrintError("INPUTに必要な処理をNOSKIP~ENDNOSKIPで囲むか、SKIPDISP 0~SKIPDISP 1で囲ってください");
+							throw new CodeEE("無限ループに入る可能性が高いため実行を終了します");
+						}
+						continue;
+					}
+					if (func.Function.Instruction != null)
+						func.Function.Instruction.DoInstruction(exm, func, state, translate);
+					else if (func.Function.IsFlowContorol())
+						doFlowControlFunction(func);
+					else
+						doNormalFunction(func);
+				}
+				else if ((line is NullLine) || (line is FunctionLabelLine))
+				{//(関数終端) or ファイル終端
+					//if (sequential)
+					//{//流れ落ちてきた
+					if (!state.IsFunctionMethod)
+						vEvaluator.RESULT = 0;
+					state.Return(0);
+					//}
+					//1750 飛んできた直後にShiftNextが入るのでここが実行されることは無いはず
+					//else//CALLやJUMPで飛んできた
+					//return;
+				}
+				else if (line is GotoLabelLine)
+					continue;//$ラベル。何もすることはない。
+				else if (line is InvalidLine)
+				{
+					if (string.IsNullOrEmpty(line.ErrMes))
+						throw new CodeEE("読込に失敗した行が実行されました。エラーの詳細は読込時の警告を参照してください。");
+					throw new CodeEE(line.ErrMes);
+				}
+				//現在そんなものはない
+				//else
+				//	throw new ExeEE("定義されていない種類の行です");
+				if (!console.IsRunning || state.ScriptEnd)
+					return;
+			}
+		}
+
+		public void DoDebugNormalFunction(InstructionLine func, bool munchkin)
+		{
+			if (func.Function.Instruction != null)
+				func.Function.Instruction.DoInstruction(exm, func, state);
+			else
+				doNormalFunction(func);
+			if (munchkin)
+				vEvaluator.IamaMunchkin();
+		}
+
+		#region normal
+		void doNormalFunction(InstructionLine func)
+		{
+			Int64 iValue = 0;
+			string str = null;
+			IOperandTerm term = null;
+			switch (func.FunctionCode)
+			{
+
+				case FunctionCode.PRINTBUTTON://変数の内容
+					{
+						if (skipPrint)
+							break;
+						SpButtonArgument bArg = (SpButtonArgument)func.Argument;
+						str = bArg.PrintStrTerm.GetStrValue(exm);
+						//ボタン処理に絡んで表示がおかしくなるため、PRINTBUTTONでの改行コードはオミット
+						str = str.Replace("\n", "");
+						if (bArg.ButtonWord.GetOperandType() == typeof(long))
+							exm.Console.PrintButton(str, bArg.ButtonWord.GetIntValue(exm));
+						else
+							exm.Console.PrintButton(str, bArg.ButtonWord.GetStrValue(exm));
+					}
+					break;
+				case FunctionCode.PRINTBUTTONC://変数の内容
+				case FunctionCode.PRINTBUTTONLC:
+					{
+						if (skipPrint)
+							break;
+						SpButtonArgument bArg = (SpButtonArgument)func.Argument;
+						str = bArg.PrintStrTerm.GetStrValue(exm);
+						//ボタン処理に絡んで表示がおかしくなるため、PRINTBUTTONでの改行コードはオミット
+						str = str.Replace("\n", "");
+						bool isRight = (func.FunctionCode == FunctionCode.PRINTBUTTONC) ? true : false;
+						if (bArg.ButtonWord.GetOperandType() == typeof(long))
+							exm.Console.PrintButtonC(str, bArg.ButtonWord.GetIntValue(exm), isRight);
+						else
+							exm.Console.PrintButtonC(str, bArg.ButtonWord.GetStrValue(exm), isRight);
+					}
+					break;
+				case FunctionCode.PRINTPLAIN:
+				case FunctionCode.PRINTPLAINFORM:
+					{
+						if (skipPrint)
+							break;
+						//Bartoum : This is where printplain print from so we always translate
+						term = ((ExpressionArgument)func.Argument).Term;
+						exm.Console.PrintPlain(term.GetStrValue(exm, true));
+					}
+					break;
+				case FunctionCode.DRAWLINE://画面の左端から右端まで----と線を引く。
+					if (skipPrint)
+						break;
+					exm.Console.PrintBar();
+					exm.Console.NewLine();
+					break;
+				case FunctionCode.CUSTOMDRAWLINE:
+				case FunctionCode.DRAWLINEFORM:
+					{
+						if (skipPrint)
+							break;
+						term = ((ExpressionArgument)func.Argument).Term;
+						str = term.GetStrValue(exm);
+						exm.Console.printCustomBar(str);
+						//exm.Console.setStBar(str);
+						//exm.Console.PrintBar();
+						exm.Console.NewLine();
+						//exm.Console.setStBar(Config.DrawLineString);
+					}
+					break;
+				case FunctionCode.PRINT_ABL://能力。引数は登録番号
+				case FunctionCode.PRINT_TALENT://素質
+				case FunctionCode.PRINT_MARK://刻印
+				case FunctionCode.PRINT_EXP://経験
+					{
+						if (skipPrint)
+							break;
+						ExpressionArgument intExpArg = (ExpressionArgument)func.Argument;
+						Int64 target = intExpArg.Term.GetIntValue(exm);
+						exm.Console.Print(vEvaluator.GetCharacterDataString(target, func.FunctionCode));
+						exm.Console.NewLine();
+					}
+					break;
+				case FunctionCode.PRINT_PALAM://パラメータ
+					{
+						if (skipPrint)
+							break;
+						ExpressionArgument intExpArg = (ExpressionArgument)func.Argument;
+						Int64 target = intExpArg.Term.GetIntValue(exm);
+						int count = 0;
+						///100以降は否定の珠とかなので表示しない
+						for (int i = 0; i < 100; i++)
+						{
+							string printStr = vEvaluator.GetCharacterParamString(target, i);
+							if (printStr != null)
+							{
+								//Need a function for each PRINT_ 
+								//Bartoum
+								exm.Console.PrintC(printStr, true);
+								count++;
+								if ((Config.PrintCPerLine > 0) && (count % Config.PrintCPerLine == 0))
+									exm.Console.PrintFlush(false);
+							}
+						}
+						exm.Console.PrintFlush(false);
+						exm.Console.RefreshStrings(false);
+					}
+					break;
+				case FunctionCode.PRINT_ITEM://所持アイテム
+					if (skipPrint)
+						break;
+					exm.Console.Print(vEvaluator.GetHavingItemsString());
+					exm.Console.NewLine();
+					break;
+				case FunctionCode.PRINT_SHOPITEM://ショップで売っているアイテム
+					{
+						if (skipPrint)
+							break;
+						int length = Math.Min(vEvaluator.ITEMSALES.Length, vEvaluator.ITEMNAME.Length);
+						if (length > vEvaluator.ITEMPRICE.Length)
+							length = vEvaluator.ITEMPRICE.Length;
+						int count = 0;
+						for (int i = 0; i < length; i++)
+						{
+							if (vEvaluator.ItemSales(i))
+							{
+								string printStr = vEvaluator.ITEMNAME[i];
+								if (printStr == null)
+									printStr = "";
+								Int64 price = vEvaluator.ITEMPRICE[i];
+                                // 1.52a改変部分 (単位の差し替えおよび前置、後置に対応)
+                                printStr = Translation.translate(printStr, "Item", true);
+                                if (Config.MoneyFirst)
+									exm.Console.PrintC(string.Format("[{2}] {0}({3}{1})", printStr, price, i, Config.MoneyLabel), false);
+								else
+									exm.Console.PrintC(string.Format("[{2}] {0}({1}{3})", printStr, price, i, Config.MoneyLabel), false);
+								count++;
+								if ((Config.PrintCPerLine > 0) && (count % Config.PrintCPerLine == 0))
+									exm.Console.PrintFlush(false);
+							}
+						}
+						exm.Console.PrintFlush(false);
+						exm.Console.RefreshStrings(false);
+					}
+					break;
+				case FunctionCode.UPCHECK://パラメータの変動
+					vEvaluator.UpdateInUpcheck(exm.Console, skipPrint);
+					break;
+				case FunctionCode.CUPCHECK://パラメータの変動(任意キャラ版)
+					{
+						ExpressionArgument intExpArg = (ExpressionArgument)func.Argument;
+						Int64 target = intExpArg.Term.GetIntValue(exm);
+						vEvaluator.CUpdateInUpcheck(exm.Console, target, skipPrint);
+					}
+					break;
+				case FunctionCode.DELALLCHARA:
+					{
+						vEvaluator.DelAllCharacter();
+						break;
+					}
+				case FunctionCode.PICKUPCHARA:
+					{
+						ExpressionArrayArgument intExpArg = (ExpressionArrayArgument)func.Argument;
+						Int64[] NoList = new Int64[intExpArg.TermList.Length];
+						Int64 charaNum = vEvaluator.CHARANUM;
+						for (int i = 0; i < intExpArg.TermList.Length; i++)
+						{
+							IOperandTerm term_i = intExpArg.TermList[i];
+							NoList[i] = term_i.GetIntValue(exm);
+							if (!(term_i is VariableTerm) || ((((VariableTerm)term_i).Identifier.Code != VariableCode.MASTER) && (((VariableTerm)term_i).Identifier.Code != VariableCode.ASSI) && (((VariableTerm)term_i).Identifier.Code != VariableCode.TARGET)))
+								if (NoList[i] < 0 || NoList[i] >= charaNum)
+									throw new CodeEE("命令PICKUPCHARAの第" + (i + 1) + "引数にキャラリストの範囲外の値(" + NoList[i] + ")が与えられました");
+						}
+						vEvaluator.PickUpChara(NoList);
+					}
+					break;
+				case FunctionCode.ADDDEFCHARA:
+					{
+						//デバッグコマンドなら通す
+						if ((func.ParentLabelLine != null) && (func.ParentLabelLine.LabelName != "SYSTEM_TITLE"))
+							throw new CodeEE("@SYSTEM_TITLE以外でこの命令を使うことはできません");
+						vEvaluator.AddCharacterFromCsvNo(0);
+						if (GlobalStatic.GameBaseData.DefaultCharacter > 0)
+							vEvaluator.AddCharacterFromCsvNo(GlobalStatic.GameBaseData.DefaultCharacter);
+						break;
+					}
+				case FunctionCode.PUTFORM://@SAVEINFO関数でのみ使用可能。PRINTFORMと同様の書式でセーブデータに概要をつける。
+					{
+						term = ((ExpressionArgument)func.Argument).Term;
+						str = term.GetStrValue(exm);
+						if (vEvaluator.SAVEDATA_TEXT != null)
+							vEvaluator.SAVEDATA_TEXT += str;
+						else
+							vEvaluator.SAVEDATA_TEXT = str;
+						break;
+					}
+				case FunctionCode.QUIT://ゲームを終了
+					exm.Console.Quit();
+					break;
+
+				case FunctionCode.VARSIZE:
+					{
+						SpVarsizeArgument versizeArg = (SpVarsizeArgument)func.Argument;
+						VariableToken varID = versizeArg.VariableID;
+						vEvaluator.VarSize(varID);
+					}
+					break;
+				case FunctionCode.SAVEDATA:
+					{
+						SpSaveDataArgument spSavedataArg = (SpSaveDataArgument)func.Argument;
+						Int64 target = spSavedataArg.Target.GetIntValue(exm);
+						if (target < 0)
+							throw new CodeEE("SAVEDATAの引数に負の値(" + target + ")が指定されました");
+						if (target > int.MaxValue)
+							throw new CodeEE("SAVEDATAの引数(" + target + ")が大きすぎます");
+						string savemes = spSavedataArg.StrExpression.GetStrValue(exm);
+						if (savemes.Contains("\n"))
+							throw new CodeEE("SAVEDATAのセーブテキストに改行文字が与えられました(セーブデータが破損するため改行文字は使えません)");
+						if (!vEvaluator.SaveTo((int)target, savemes))
+						{
+							console.PrintError("SAVEDATA命令によるセーブ中に予期しないエラーが発生しました");
+						}
+					}
+					break;
+
+				case FunctionCode.POWER:
+					{
+						SpPowerArgument powerArg = (SpPowerArgument)func.Argument;
+						double x = powerArg.X.GetIntValue(exm);
+						double y = powerArg.Y.GetIntValue(exm);
+						double pow = Math.Pow(x, y);
+						if (double.IsNaN(pow))
+							throw new CodeEE("累乗結果が非数値です");
+						if (double.IsInfinity(pow))
+							throw new CodeEE("累乗結果が無限大です");
+						if ((pow >= Int64.MaxValue) || (pow <= Int64.MinValue))
+							throw new CodeEE("累乗結果(" + pow + ")が64ビット符号付き整数の範囲外です");
+						powerArg.VariableDest.SetValue((long)pow, exm);
+						break;
+					}
+				case FunctionCode.SWAP:
+					{
+						SpSwapVarArgument arg = (SpSwapVarArgument)func.Argument;
+						//1756beta2+v11
+						//値を読み出す前に添え字を確定させておかないと、RANDが添え字にある場合正しく処理できない
+						FixedVariableTerm vTerm1 = arg.var1.GetFixedVariableTerm(exm);
+						FixedVariableTerm vTerm2 = arg.var2.GetFixedVariableTerm(exm);
+						if (vTerm1.GetOperandType() != vTerm2.GetOperandType())
+							throw new CodeEE("入れ替える変数の型が異なります");
+						if (vTerm1.GetOperandType() == typeof(Int64))
+						{
+							Int64 temp = vTerm1.GetIntValue(exm);
+							vTerm1.SetValue(vTerm2.GetIntValue(exm), exm);
+							vTerm2.SetValue(temp, exm);
+						}
+						else if (arg.var1.GetOperandType() == typeof(string))
+						{
+							string temps = vTerm1.GetStrValue(exm);
+							vTerm1.SetValue(vTerm2.GetStrValue(exm), exm);
+							vTerm2.SetValue(temps, exm);
+						}
+						else
+						{
+							throw new CodeEE("不明な変数型です");
+						}
+						break;
+					}
+				case FunctionCode.GETTIME:
+					{
+						long date = DateTime.Now.Year;
+						date = date * 100 + DateTime.Now.Month;
+						date = date * 100 + DateTime.Now.Day;
+						date = date * 100 + DateTime.Now.Hour;
+						date = date * 100 + DateTime.Now.Minute;
+						date = date * 100 + DateTime.Now.Second;
+						date = date * 1000 + DateTime.Now.Millisecond;
+						vEvaluator.RESULT = date;//17桁。2京くらい。
+						vEvaluator.RESULTS = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
+					}
+					break;
+				case FunctionCode.SETCOLOR:
+					{
+						SpColorArgument colorArg = (SpColorArgument)func.Argument;
+						Int64 colorR;
+						Int64 colorG;
+						Int64 colorB;
+						if (colorArg.RGB != null)
+						{
+							Int64 colorRGB = colorArg.RGB.GetIntValue(exm);
+							colorR = (colorRGB & 0xFF0000) >> 16;
+							colorG = (colorRGB & 0x00FF00) >> 8;
+							colorB = (colorRGB & 0x0000FF);
+						}
+						else
+						{
+							colorR = colorArg.R.GetIntValue(exm);
+							colorG = colorArg.G.GetIntValue(exm);
+							colorB = colorArg.B.GetIntValue(exm);
+							if ((colorR < 0) || (colorG < 0) || (colorB < 0))
+								throw new CodeEE("SETCOLORの引数に0未満の値が指定されました");
+							if ((colorR > 255) || (colorG > 255) || (colorB > 255))
+								throw new CodeEE("SETCOLORの引数に255を超える値が指定されました");
+						}
+						Color c = Color.FromArgb((Int32)colorR, (Int32)colorG, (Int32)colorB);
+						exm.Console.SetStringStyle(c);
+					}
+					break;
+				case FunctionCode.SETCOLORBYNAME:
+					{
+						string colorName = func.Argument.ConstStr;
+						Color c = Color.FromName(colorName);
+						if (c.A == 0)
+						{
+							if (str.Equals("transparent", StringComparison.OrdinalIgnoreCase))
+								throw new CodeEE("無色透明(Transparent)は色として指定できません");
+							throw new CodeEE("指定された色名\"" + colorName + "\"は無効な色名です");
+						}
+						exm.Console.SetStringStyle(c);
+					}
+					break;
+				case FunctionCode.SETBGCOLOR:
+					{
+						SpColorArgument colorArg = (SpColorArgument)func.Argument;
+						Int64 colorR;
+						Int64 colorG;
+						Int64 colorB;
+						if (colorArg.IsConst)
+						{
+							Int64 colorRGB = colorArg.ConstInt;
+							colorR = (colorRGB & 0xFF0000) >> 16;
+							colorG = (colorRGB & 0x00FF00) >> 8;
+							colorB = (colorRGB & 0x0000FF);
+						}
+						else if (colorArg.RGB != null)
+						{
+							Int64 colorRGB = colorArg.RGB.GetIntValue(exm);
+							colorR = (colorRGB & 0xFF0000) >> 16;
+							colorG = (colorRGB & 0x00FF00) >> 8;
+							colorB = (colorRGB & 0x0000FF);
+						}
+						else
+						{
+							colorR = colorArg.R.GetIntValue(exm);
+							colorG = colorArg.G.GetIntValue(exm);
+							colorB = colorArg.B.GetIntValue(exm);
+							if ((colorR < 0) || (colorG < 0) || (colorB < 0))
+								throw new CodeEE("SETCOLORの引数に0未満の値が指定されました");
+							if ((colorR > 255) || (colorG > 255) || (colorB > 255))
+								throw new CodeEE("SETCOLORの引数に255を超える値が指定されました");
+						}
+						Color c = Color.FromArgb((Int32)colorR, (Int32)colorG, (Int32)colorB);
+						exm.Console.SetBgColor(c);
+					}
+					break;
+				case FunctionCode.SETBGCOLORBYNAME:
+					{
+						string colorName = func.Argument.ConstStr;
+						Color c = Color.FromName(colorName);
+						if (c.A == 0)
+						{
+							if (str.Equals("transparent", StringComparison.OrdinalIgnoreCase))
+								throw new CodeEE("無色透明(Transparent)は色として指定できません");
+							throw new CodeEE("指定された色名\"" + colorName + "\"は無効な色名です");
+						}
+						exm.Console.SetBgColor(c);
+					}
+					break;
+				case FunctionCode.FONTSTYLE:
+					{
+						FontStyle fs = FontStyle.Regular;
+						if (func.Argument.IsConst)
+							iValue = func.Argument.ConstInt;
+						else
+							iValue = ((ExpressionArgument)func.Argument).Term.GetIntValue(exm);
+						if ((iValue & 1) != 0)
+							fs |= FontStyle.Bold;
+						if ((iValue & 2) != 0)
+							fs |= FontStyle.Italic;
+						if ((iValue & 4) != 0)
+							fs |= FontStyle.Strikeout;
+						if ((iValue & 8) != 0)
+							fs |= FontStyle.Underline;
+						exm.Console.SetStringStyle(fs);
+					}
+					break;
+				case FunctionCode.SETFONT:
+					if (func.Argument.IsConst)
+						str = func.Argument.ConstStr;
+					else
+						str = ((ExpressionArgument)func.Argument).Term.GetStrValue(exm);
+					exm.Console.SetFont(str);
+					break;
+				case FunctionCode.ALIGNMENT:
+					str = func.Argument.ConstStr;
+					if (str.Equals("LEFT", Config.SCVariable))
+						exm.Console.Alignment = DisplayLineAlignment.LEFT;
+					else if (str.Equals("CENTER", Config.SCVariable))
+						exm.Console.Alignment = DisplayLineAlignment.CENTER;
+					else if (str.Equals("RIGHT", Config.SCVariable))
+						exm.Console.Alignment = DisplayLineAlignment.RIGHT;
+					else
+						throw new CodeEE("ALIGNMENTのキーワード\"" + str + "\"は未定義です");
+					break;
+
+				case FunctionCode.REDRAW:
+					if (func.Argument.IsConst)
+						iValue = func.Argument.ConstInt;
+					else
+						iValue = ((ExpressionArgument)func.Argument).Term.GetIntValue(exm);
+					exm.Console.SetRedraw(iValue);
+					break;
+
+				case FunctionCode.RESET_STAIN:
+					{
+						if (func.Argument.IsConst)
+							iValue = func.Argument.ConstInt;
+						else
+							iValue = ((ExpressionArgument)func.Argument).Term.GetIntValue(exm);
+						vEvaluator.SetDefaultStain(iValue);
+					}
+					break;
+				case FunctionCode.SPLIT:
+					{
+						SpSplitArgument spSplitArg = (SpSplitArgument)func.Argument;
+						string target = spSplitArg.TargetStr.GetStrValue(exm);
+						string[] split = { spSplitArg.Split.GetStrValue(exm) };
+						string[] retStr = target.Split(split, StringSplitOptions.None);
+						spSplitArg.Num.SetValue(retStr.Length, exm);
+						if (retStr.Length > spSplitArg.Var.GetLength(0))
+						{
+							string[] temp = retStr;
+							retStr = new string[spSplitArg.Var.GetLength(0)];
+							Array.Copy(temp, retStr, retStr.Length);
+							//throw new CodeEE("SPLITによる分割後の文字列の数が配列変数の要素数を超えています");
+						}
+						spSplitArg.Var.SetValue(retStr, new long[] { 0, 0, 0 });
+					}
+					break;
+				case FunctionCode.PRINTCPERLINE:
+					{
+						SpGetIntArgument spGetintArg = (SpGetIntArgument)func.Argument;
+						spGetintArg.VarToken.SetValue(Config.PrintCPerLine, exm);
+					}
+					break;
+				case FunctionCode.SAVENOS:
+					{
+						SpGetIntArgument spGetintArg = (SpGetIntArgument)func.Argument;
+						spGetintArg.VarToken.SetValue(Config.SaveDataNos, exm);
+					}
+					break;
+				case FunctionCode.FORCEKANA:
+					if (func.Argument.IsConst)
+						iValue = func.Argument.ConstInt;
+					else
+						iValue = ((ExpressionArgument)func.Argument).Term.GetIntValue(exm);
+					exm.ForceKana(iValue);
+					break;
+				case FunctionCode.SKIPDISP:
+					{
+						iValue = (func.Argument.IsConst) ? func.Argument.ConstInt : ((ExpressionArgument)func.Argument).Term.GetIntValue(exm);
+						skipPrint = (iValue != 0);
+						userDefinedSkip = (iValue != 0);
+						vEvaluator.RESULT = (skipPrint) ? 1L : 0L;
+					}
+					break;
+				case FunctionCode.NOSKIP:
+					{
+						if (func.JumpTo == null)
+							throw new CodeEE("対応するENDNOSKIPのないNOSKIPです");
+						saveSkip = skipPrint;
+						if (skipPrint)
+							skipPrint = false;
+					}
+					break;
+				case FunctionCode.ENDNOSKIP:
+					{
+						if (func.JumpTo == null)
+							throw new CodeEE("対応するNOSKIPのないENDNOSKIPです");
+						if (saveSkip)
+							skipPrint = true;
+					}
+					break;
+				case FunctionCode.OUTPUTLOG:
+					exm.Console.OutputLog(null);
+					break;
+				case FunctionCode.ARRAYSHIFT: //配列要素をずらす
+					{
+						SpArrayShiftArgument arrayArg = (SpArrayShiftArgument)func.Argument;
+						if (!arrayArg.VarToken.Identifier.IsArray1D)
+							throw new CodeEE("ARRAYSHIFTは1次元配列および配列型キャラクタ変数のみに対応しています");
+						FixedVariableTerm dest = arrayArg.VarToken.GetFixedVariableTerm(exm);
+						int shift = (int)arrayArg.Num1.GetIntValue(exm);
+						if (shift == 0)
+							break;
+						int start = (int)arrayArg.Num3.GetIntValue(exm);
+						if (start < 0)
+							throw new CodeEE("ARRAYSHIFTの第4引数が負の値(" + start + ")です");
+						int num;
+						if (arrayArg.Num4 != null)
+						{
+							num = (int)arrayArg.Num4.GetIntValue(exm);
+							if (num < 0)
+								throw new CodeEE("ARRAYSHIFTの第5引数が負の値(" + start + ")です");
+							if (num == 0)
+								break;
+						}
+						else
+							num = -1;
+						if (dest.Identifier.IsInteger)
+						{
+							Int64 def = arrayArg.Num2.GetIntValue(exm);
+							vEvaluator.ShiftArray(dest, shift, def, start, num);
+						}
+						else
+						{
+							string defs = arrayArg.Num2.GetStrValue(exm);
+							vEvaluator.ShiftArray(dest, shift, defs, start, num);
+						}
+						break;
+					}
+				case FunctionCode.ARRAYREMOVE:
+					{
+						SpArrayControlArgument arrayArg = (SpArrayControlArgument)func.Argument;
+						if (!arrayArg.VarToken.Identifier.IsArray1D)
+							throw new CodeEE("ARRAYREMOVEは1次元配列および配列型キャラクタ変数のみに対応しています");
+						FixedVariableTerm p = arrayArg.VarToken.GetFixedVariableTerm(exm);
+						int start = (int)arrayArg.Num1.GetIntValue(exm);
+						int num = (int)arrayArg.Num2.GetIntValue(exm);
+						if (start < 0)
+							throw new CodeEE("ARRAYREMOVEの第2引数が負の値(" + start + ")です");
+						if (num < 0)
+							throw new CodeEE("ARRAYREMOVEの第3引数が負の値(" + start + ")です");
+						if (num == 0)
+							break;
+						vEvaluator.RemoveArray(p, start, num);
+						break;
+					}
+				case FunctionCode.ARRAYSORT:
+					{
+						SpArraySortArgument arrayArg = (SpArraySortArgument)func.Argument;
+						if (!arrayArg.VarToken.Identifier.IsArray1D)
+							throw new CodeEE("ARRAYRESORTは1次元配列および配列型キャラクタ変数のみに対応しています");
+						FixedVariableTerm p = arrayArg.VarToken.GetFixedVariableTerm(exm);
+						int start = (int)arrayArg.Num1.GetIntValue(exm);
+						if (start < 0)
+							throw new CodeEE("ARRAYSORTの第3引数が負の値(" + start + ")です");
+						int num = 0;
+						if (arrayArg.Num2 != null)
+						{
+							num = (int)arrayArg.Num2.GetIntValue(exm);
+							if (num < 0)
+								throw new CodeEE("ARRAYSORTの第4引数が負の値(" + start + ")です");
+							if (num == 0)
+								break;
+						}
+						else
+							num = -1;
+						vEvaluator.SortArray(p, arrayArg.Order, start, num);
+						break;
+					}
+				case FunctionCode.ARRAYCOPY:
+					{
+						SpCopyArrayArgument arrayArg = (SpCopyArrayArgument)func.Argument;
+						IOperandTerm varName1 = arrayArg.VarName1;
+						IOperandTerm varName2 = arrayArg.VarName2;
+						VariableToken[] vars = new VariableToken[2] { null, null };
+						if (!(varName1 is SingleTerm) || !(varName2 is SingleTerm))
+						{
+							string[] names = new string[2] { null, null };
+							names[0] = varName1.GetStrValue(exm);
+							names[1] = varName2.GetStrValue(exm);
+							if ((vars[0] = GlobalStatic.IdentifierDictionary.GetVariableToken(names[0], null, true)) == null)
+								throw new CodeEE("ARRAYCOPY命令の第1引数(" + names[0] + ")が有効な変数名ではありません");
+							if (!vars[0].IsArray1D && !vars[0].IsArray2D && !vars[0].IsArray3D)
+								throw new CodeEE("ARRAYCOPY命令の第1引数\"" + names[0] + "\"は配列変数ではありません");
+							if (vars[0].IsCharacterData)
+								throw new CodeEE("ARRAYCOPY命令の第1引数\"" + names[0] + "\"はキャラクタ変数です(対応していません)");
+							if ((vars[1] = GlobalStatic.IdentifierDictionary.GetVariableToken(names[1], null, true)) == null)
+								throw new CodeEE("ARRAYCOPY命令の第2引数(" + names[0] + ")が有効な変数名ではありません");
+							if (!vars[1].IsArray1D && !vars[1].IsArray2D && !vars[1].IsArray3D)
+								throw new CodeEE("ARRAYCOPY命令の第2引数\"" + names[1] + "\"は配列変数ではありません");
+							if (vars[1].IsCharacterData)
+								throw new CodeEE("ARRAYCOPY命令の第2引数\"" + names[1] + "\"はキャラクタ変数です(対応していません)");
+							if (vars[1].IsConst)
+								throw new CodeEE("ARRAYCOPY命令の第2引数\"" + names[1] + "\"は値を変更できない変数です");
+							if ((vars[0].IsArray1D && !vars[1].IsArray1D) || (vars[0].IsArray2D && !vars[1].IsArray2D) || (vars[0].IsArray3D && !vars[1].IsArray3D))
+								throw new CodeEE("ARRAYCOPY命令の2つの配列変数の次元数が一致していません");
+							if ((vars[0].IsInteger && vars[1].IsString) || (vars[0].IsString && vars[1].IsInteger))
+								throw new CodeEE("ARRAYCOPY命令の2つの配列変数の型が一致していません");
+						}
+						else
+						{
+							vars[0] = GlobalStatic.IdentifierDictionary.GetVariableToken(((SingleTerm)varName1).Str, null, true);
+							vars[1] = GlobalStatic.IdentifierDictionary.GetVariableToken(((SingleTerm)varName2).Str, null, true);
+							if ((vars[0].IsInteger && vars[1].IsString) || (vars[0].IsString && vars[1].IsInteger))
+								throw new CodeEE("ARRAYCOPY命令の2つの配列変数の型が一致していません");
+						}
+						vEvaluator.CopyArray(vars[0], vars[1]);
+					}
+					break;
+				case FunctionCode.ENCODETOUNI:
+					{
+						//int length = Encoding.UTF32.GetEncoder().GetByteCount(target.ToCharArray(), 0, target.Length, false);
+						//byte[] bytes = new byte[length];
+						//Encoding.UTF32.GetEncoder().GetBytes(target.ToCharArray(), 0, target.Length, bytes, 0, false);
+						//vEvaluator.setEncodingResult(bytes);
+						term = ((ExpressionArgument)func.Argument).Term;
+						string target = term.GetStrValue(exm);
+
+						int length = vEvaluator.RESULT_ARRAY.Length;
+						// result:0には長さが入るのでその分-1
+						if (target.Length > length - 1)
+							throw new CodeEE(String.Format("ENCODETOUNIの引数が長すぎます(現在{0}文字。最大{1}文字まで)", target.Length, length - 1));
+
+						int[] ary = new int[target.Length];
+						for (int i = 0; i < target.Length; i++)
+							ary[i] = char.ConvertToUtf32(target, i);
+						vEvaluator.SetEncodingResult(ary);
+					}
+					break;
+				case FunctionCode.ASSERT:
+					if (((ExpressionArgument)func.Argument).Term.GetIntValue(exm) == 0)
+						throw new CodeEE("ASSERT文の引数が0です");
+					break;
+				case FunctionCode.THROW:
+					throw new CodeEE(((ExpressionArgument)func.Argument).Term.GetStrValue(exm));
+				case FunctionCode.CLEARTEXTBOX:
+					GlobalStatic.MainWindow.Clear_RichText();
+					break;
+				case FunctionCode.STRDATA:
+					{
+						//表示データが空なら何もしないで飛ぶ
+						if (func.dataList.Count == 0)
+						{
+							state.JumpTo(func.JumpTo);
+							return;
+						}
+						int count = func.dataList.Count;
+						int choice = (int)exm.VEvaluator.GetNextRand(count);
+						List<InstructionLine> iList = func.dataList[choice];
+						int i = 0;
+						foreach (InstructionLine selectedLine in iList)
+						{
+							state.CurrentLine = selectedLine;
+							if (selectedLine.Argument == null)
+								ArgumentParser.SetArgumentTo(selectedLine);
+							term = ((ExpressionArgument)selectedLine.Argument).Term;
+							str += term.GetStrValue(exm);
+							if (++i < iList.Count)
+								str += "\n";
+						}
+						((StrDataArgument)func.Argument).Var.SetValue(str, exm);
+						//ジャンプするが、流れが連続であることを保証。
+						state.JumpTo(func.JumpTo);
+						break;
+					}
+#if DEBUG
+				default:
+					throw new ExeEE("未定義の関数");
+#endif
+			}
+		}
+
+		bool saveSkip;
+		bool userDefinedSkip;
+
+		#endregion
+
+		#region flow control
+
+		bool doFlowControlFunction(InstructionLine func)
+		{
+			switch (func.FunctionCode)
+			{
+				case FunctionCode.LOADDATA:
+					{
+						ExpressionArgument intExpArg = (ExpressionArgument)func.Argument;
+						Int64 target = intExpArg.Term.GetIntValue(exm);
+						if (target < 0)
+							throw new CodeEE("LOADDATAの引数に負の値(" + target + ")が指定されました");
+						if (target > int.MaxValue)
+							throw new CodeEE("LOADDATAの引数(" + target + ")が大きすぎます");
+						//EraDataResult result = vEvaluator.checkData((int)target);
+						EraDataResult result = vEvaluator.CheckData((int)target, EraSaveFileType.Normal);
+						if (result.State != EraDataState.OK)
+							throw new CodeEE("不正なデータをロードしようとしました");
+
+						if (!vEvaluator.LoadFrom((int)target))
+							throw new ExeEE("ファイルのロード中に予期しないエラーが発生しました");
+						state.ClearFunctionList();
+						state.SystemState = SystemStateCode.LoadData_DataLoaded;
+						return false;
+					}
+
+				case FunctionCode.TRYCALLLIST:
+				case FunctionCode.TRYJUMPLIST:
+					{
+						//if (!sequential)//RETURNで帰ってきた
+						//{
+						//	state.JumpTo(func.JumpTo);
+						//	break;
+						//}
+						string funcName = "";
+						CalledFunction callto = null;
+						SpCallArgment cfa = null;
+						foreach (InstructionLine iLine in func.callList)
+						{
+
+							cfa = (SpCallArgment)iLine.Argument;
+							funcName = cfa.FuncnameTerm.GetStrValue(exm);
+							if (Config.ICFunction)
+								funcName = funcName.ToUpper();
+							callto = CalledFunction.CallFunction(this, funcName, func.JumpTo);
+							if (callto == null)
+								continue;
+							callto.IsJump = func.Function.IsJump();
+							string errMes;
+							UserDefinedFunctionArgument args = callto.ConvertArg(cfa.RowArgs, out errMes);
+							if (args == null)
+								throw new CodeEE(errMes);
+							state.IntoFunction(callto, args, exm);
+							return true;
+						}
+						state.JumpTo(func.JumpTo);
+					}
+					break;
+				case FunctionCode.TRYGOTOLIST:
+					{
+						string funcName = "";
+						LogicalLine jumpto = null;
+						foreach (InstructionLine iLine in func.callList)
+						{
+							if (iLine.Argument == null)
+								ArgumentParser.SetArgumentTo(iLine);
+							funcName = ((SpCallArgment)iLine.Argument).FuncnameTerm.GetStrValue(exm);
+							if (Config.ICVariable)
+								funcName = funcName.ToUpper();
+							jumpto = state.CurrentCalled.CallLabel(this, funcName);
+							if (jumpto != null)
+								break;
+						}
+						if (jumpto == null)
+							state.JumpTo(func.JumpTo);
+						else
+							state.JumpTo(jumpto);
+					}
+					break;
+				case FunctionCode.CALLTRAIN:
+					{
+						ExpressionArgument intExpArg = (ExpressionArgument)func.Argument;
+						Int64 count = intExpArg.Term.GetIntValue(exm);
+						SetCommnds(count);
+						return false;
+					}
+				case FunctionCode.STOPCALLTRAIN:
+					{
+						if (isCTrain)
+						{
+							ClearCommands();
+							skipPrint = false;
+						}
+						return false;
+					}
+				case FunctionCode.DOTRAIN:
+					{
+						switch (state.SystemState)
+						{
+							//case SystemStateCode.Train_Begin://BEGIN TRAINから。
+							case SystemStateCode.Train_CallEventTrain://@EVENTTRAINの呼び出し中。スキップ可能
+							case SystemStateCode.Train_CallShowStatus://@SHOW_STATUSの呼び出し中
+							//case SystemStateCode.Train_CallComAbleXX://@COM_ABLExxの呼び出し中。
+							case SystemStateCode.Train_CallShowUserCom://@SHOW_USERCOMの呼び出し中
+							//case SystemStateCode.Train_WaitInput://入力待ち状態。選択が実行可能ならEVENTCOMからCOMxx、そうでなければ@USERCOMにRESULTを渡す
+							//case SystemStateCode.Train_CallEventCom://@EVENTCOMの呼び出し中
+							//case SystemStateCode.Train_CallComXX://@COMxxの呼び出し中
+							//case SystemStateCode.Train_CallSourceCheck://@SOURCE_CHECKの呼び出し中
+							case SystemStateCode.Train_CallEventComEnd://@EVENTCOMENDの呼び出し中。スキップ可能。Train_CallEventTrainへ帰る。@USERCOMの呼び出し中もここ
+								break;
+							default:
+								exm.Console.PrintSystemLine(state.SystemState.ToString());
+								throw new CodeEE("DOTRAIN命令をこの位置で実行することはできません");
+						}
+						coms.Clear();
+						isCTrain = false;
+						count = 0;
+
+						Int64 train = ((ExpressionArgument)func.Argument).Term.GetIntValue(exm);
+						if (train < 0)
+							throw new CodeEE("DOTRAIN命令に0未満の値が渡されました");
+						if (train >= _trainName.Length)
+							throw new CodeEE("DOTRAIN命令にTRAINNAMEの配列数以上の値が渡されました");
+						doTrainSelectCom = train;
+						state.SystemState = SystemStateCode.Train_DoTrain;
+						return false;
+					}
+#if DEBUG
+				default:
+					throw new ExeEE("未定義の関数です");
+#endif
+			}
+			return true;
+		}
+
+
+
+
+		List<ProcessState> prevStateList = new List<ProcessState>();
+		public void saveCurrentState(bool single)
+		{
+			//怖いところだが、現状起こらない現象なので一旦消してみる
+			//if (single && (prevStateList.Count > 0))
+			//	throw new ExeEE("記憶している状態があるのに再度記憶しようとした");
+			if (state != null)
+			{
+				prevStateList.Add(state);
+				state = state.Clone();
+			}
+		}
+
+		public void loadPrevState()
+		{
+			//怖いところだが、現状起こらない現象なので一旦消してみる
+			//if (prevStateList.Count == 0)
+			//	throw new ExeEE("記憶している状態がないのに呼び戻しされた");
+			if (state != null)
+			{
+				state.ClearFunctionList();
+				state = prevStateList[prevStateList.Count - 1];
+				deletePrevState();
+			}
+		}
+
+		private void deletePrevState()
+		{
+			if (prevStateList.Count == 0)
+				return;
+			prevStateList.RemoveAt(prevStateList.Count - 1);
+		}
+
+		private void deleteAllPrevState()
+		{
+			foreach (ProcessState state in prevStateList)
+				state.ClearFunctionList();
+			prevStateList.Clear();
+		}
+
+		public ProcessState getCurrentState => state;
+
+		#endregion
+	}
+}

+ 531 - 0
NTERA/Game/GameProc/Process.State.cs

@@ -0,0 +1,531 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.Sub;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera.GameProc
+{
+	//1756 インナークラス解除して一般に開放
+
+
+	//難読化用属性。enum.ToString()やenum.Parse()を行うなら(Exclude=true)にすること。
+	[Obfuscation(Exclude = false)]
+	internal enum SystemStateCode
+	{
+		__CAN_SAVE__ = 0x10000,//セーブロード画面を呼び出し可能か?
+		__CAN_BEGIN__ = 0x20000,//BEGIN命令を呼び出し可能か?
+		Title_Begin = 0,//初期状態
+		Openning = 1,//最初の入力待ち
+		Train_Begin = 0x10,//BEGIN TRAINから。
+		Train_CallEventTrain = 0x11,//@EVENTTRAINの呼び出し中。スキップ可能
+		Train_CallShowStatus = 0x12,//@SHOW_STATUSの呼び出し中
+		Train_CallComAbleXX = 0x13,//@COM_ABLExxの呼び出し中。スキップの場合、RETURN 1とする。
+		Train_CallShowUserCom = 0x14,//@SHOW_USERCOMの呼び出し中
+		Train_WaitInput = 0x15,//入力待ち状態。選択が実行可能ならEVENTCOMからCOMxx、そうでなければ@USERCOMにRESULTを渡す
+		Train_CallEventCom = 0x16 | __CAN_BEGIN__,//@EVENTCOMの呼び出し中
+
+		Train_CallComXX = 0x17 | __CAN_BEGIN__,//@COMxxの呼び出し中
+		Train_CallSourceCheck = 0x18 | __CAN_BEGIN__,//@SOURCE_CHECKの呼び出し中
+		Train_CallEventComEnd = 0x19 | __CAN_BEGIN__,//@EVENTCOMENDの呼び出し中。スキップ可能。Train_CallEventTrainへ帰る。@USERCOMの呼び出し中もここ
+
+		Train_DoTrain = 0x1A,
+
+		AfterTrain_Begin = 0x20 | __CAN_BEGIN__,//BEGIN AFTERTRAINから。@EVENTENDを呼び出してNormalへ。
+
+		Ablup_Begin = 0x30,//BEGIN ABLUPから。
+		Ablup_CallShowJuel = 0x31,//@SHOW_JUEL
+		Ablup_CallShowAblupSelect = 0x32,//@SHOW_ABLUP_SELECT
+		Ablup_WaitInput = 0x33,//
+		Ablup_CallAblupXX = 0x34 | __CAN_BEGIN__,//@ABLUPxxがない場合は、@USERABLUPにRESULTを渡す。Ablup_CallShowJuelへ戻る。
+
+		Turnend_Begin = 0x40 | __CAN_BEGIN__,//BEGIN TURNENDから。@EVENTTURNENDを呼び出してNormalへ。
+
+		Shop_Begin = 0x50 | __CAN_SAVE__,//BEGIN SHOPから
+		Shop_CallEventShop = 0x51 | __CAN_BEGIN__ | __CAN_SAVE__,//@EVENTSHOPの呼び出し中。スキップ可能
+		Shop_CallShowShop = 0x52 | __CAN_SAVE__,//@SHOW_SHOPの呼び出し中
+		Shop_WaitInput = 0x53 | __CAN_SAVE__,//入力待ち状態。アイテムが存在するならEVENTBUYにBOUGHT、そうでなければ@USERSHOPにRESULTを渡す
+		Shop_CallEventBuy = 0x54 | __CAN_BEGIN__ | __CAN_SAVE__,//@USERSHOPまた@EVENTBUYはの呼び出し中
+
+		SaveGame_Begin = 0x100,//SAVEGAMEから
+		SaveGame_WaitInput = 0x101,//入力待ち
+		SaveGame_WaitInputOverwrite = 0x102,//上書きの許可待ち
+		SaveGame_CallSaveInfo = 0x103,//@SAVEINFO呼び出し中。20回。
+		LoadGame_Begin = 0x110,//LOADGAMEから
+		LoadGame_WaitInput = 0x111,//入力待ち
+		LoadGameOpenning_Begin = 0x120,//最初に[1]を選択したとき。
+		LoadGameOpenning_WaitInput = 0x121,//入力待ち
+
+
+		//AutoSave_Begin = 0x200,
+		AutoSave_CallSaveInfo = 0x201,
+		AutoSave_CallUniqueAutosave = 0x202,
+		AutoSave_Skipped = 0x203,
+
+		LoadData_DataLoaded = 0x210,//データロード直後
+		LoadData_CallSystemLoad = 0x211 | __CAN_BEGIN__,//データロード直後
+		LoadData_CallEventLoad = 0x212 | __CAN_BEGIN__,//@EVENTLOADの呼び出し中。スキップ可能
+
+		Openning_TitleLoadgame = 0x220,
+
+		System_Reloaderb = 0x230,
+		First_Begin = 0x240,
+
+		Normal = 0xFFFF | __CAN_BEGIN__ | __CAN_SAVE__//特に何でもないとき。ScriptEndに達したらエラー
+	}
+
+	//難読化用属性。enum.ToString()やenum.Parse()を行うなら(Exclude=true)にすること。
+	[Obfuscation(Exclude = false)]
+	internal enum BeginType
+	{
+		NULL = 0,
+		SHOP = 2,
+		TRAIN = 3,
+		AFTERTRAIN = 4,
+		ABLUP = 5,
+		TURNEND = 6,
+		FIRST = 7,
+		TITLE = 8
+	}
+
+	internal sealed class ProcessState
+	{
+		public ProcessState(IConsole console)
+		{
+			if (Program.DebugMode)//DebugModeでなければ知らなくて良い
+				this.console = console;
+		}
+		readonly IConsole console;
+		readonly List<CalledFunction> functionList = new List<CalledFunction>();
+		private LogicalLine currentLine;
+		//private LogicalLine nextLine;
+		public int lineCount;
+        public int currentMin = 0;
+        //private bool sequential;
+
+		public bool ScriptEnd => functionList.Count == currentMin;
+
+		public int functionCount => functionList.Count;
+
+		SystemStateCode sysStateCode = SystemStateCode.Title_Begin;
+		BeginType begintype = BeginType.NULL;
+		public bool isBegun => (begintype != BeginType.NULL) ? true : false;
+
+		public LogicalLine CurrentLine { get => currentLine;
+			set { currentLine = value; } }
+        public LogicalLine ErrorLine => currentLine;
+
+		//IF文中でELSEIF文の中身をチェックするなどCurrentLineと作業中のLineが違う時にセットする
+		//public LogicalLine RunningLine { get; set; }
+		//1755a 呼び出し元消滅
+		//public bool Sequential { get { return sequential; } }
+		public CalledFunction CurrentCalled => functionList[functionList.Count - 1];
+
+		public SystemStateCode SystemState
+		{
+			get => sysStateCode;
+			set { sysStateCode = value; }
+		}
+
+		public void ShiftNextLine()
+		{
+            currentLine = currentLine.NextLine;
+            //nextLine = nextLine.NextLine;
+            //RunningLine = null;
+            //sequential = true;
+			//GlobalStatic.Process.lineCount++;
+			lineCount++;
+		}
+
+		/// <summary>
+		/// 関数内の移動。JUMPではなくGOTOやIF文など
+		/// </summary>
+		/// <param name="line"></param>
+		public void JumpTo(LogicalLine line)
+		{
+            currentLine = line;
+            lineCount++;
+            //sequential = false;
+			//ShfitNextLine();
+		}
+
+		public void SetBegin(string keyword)
+		{//TrimとToUpper済みのはず
+			switch (keyword)
+			{
+				case "SHOP":
+					SetBegin(BeginType.SHOP); return;
+				case "TRAIN":
+					SetBegin(BeginType.TRAIN); return;
+				case "AFTERTRAIN":
+					SetBegin(BeginType.AFTERTRAIN); return;
+				case "ABLUP":
+					SetBegin(BeginType.ABLUP); return;
+				case "TURNEND":
+					SetBegin(BeginType.TURNEND); return;
+				case "FIRST":
+					SetBegin(BeginType.FIRST); return;
+				case "TITLE":
+					SetBegin(BeginType.TITLE); return;
+			}
+			throw new CodeEE("BEGINのキーワード\"" + keyword + "\"は未定義です");
+		}
+
+		public void SetBegin(BeginType type)
+		{
+			string errmes = "";
+			switch (type)
+			{
+				case BeginType.SHOP:
+				case BeginType.TRAIN:
+				case BeginType.AFTERTRAIN:
+				case BeginType.ABLUP:
+				case BeginType.TURNEND:
+				case BeginType.FIRST:
+					if ((sysStateCode & SystemStateCode.__CAN_BEGIN__) != SystemStateCode.__CAN_BEGIN__)
+					{
+						errmes = "BEGIN";
+						goto err;
+					}
+					break;
+				//1.729 BEGIN TITLEはどこでも使えるように
+				case BeginType.TITLE:
+					break;
+				//BEGINの処理中でチェック済み
+				//default:
+				//    throw new ExeEE("不適当なBEGIN呼び出し");
+			}
+			begintype = type;
+			return;
+		err:
+			CalledFunction func = functionList[0];
+			string funcName = func.FunctionName;
+			throw new CodeEE("@" + funcName + "中で" + errmes + "命令を実行することはできません");
+		}
+
+		public void SaveLoadData(bool saveData)
+		{
+
+			if (saveData)
+				sysStateCode = SystemStateCode.SaveGame_Begin;
+			else
+				sysStateCode = SystemStateCode.LoadGame_Begin;
+			//ClearFunctionList();
+		}
+
+		public void ClearFunctionList()
+		{
+			if (Program.DebugMode && !isClone && GlobalStatic.Process.MethodStack() == 0)
+				console.DebugClearTraceLog();
+			foreach (CalledFunction called in functionList)
+                if (called.CurrentLabel.hasPrivDynamicVar)
+                    called.CurrentLabel.Out();
+			functionList.Clear();
+			begintype = BeginType.NULL;
+		}
+
+		public bool calledWhenNormal = true;
+		/// <summary>
+		/// BEGIN命令によるプログラム状態の変化
+		/// </summary>
+		/// <param name="key"></param>
+		/// <returns></returns>
+		public void Begin()
+		{
+			//@EVENTSHOPからの呼び出しは一旦破棄
+			if (sysStateCode == SystemStateCode.Shop_CallEventShop)
+				return;
+
+			switch (begintype)
+			{
+				case BeginType.SHOP:
+					if (sysStateCode == SystemStateCode.Normal)
+						calledWhenNormal = true;
+					else
+						calledWhenNormal = false;
+					sysStateCode = SystemStateCode.Shop_Begin;
+					break;
+				case BeginType.TRAIN:
+					sysStateCode = SystemStateCode.Train_Begin;
+					break;
+				case BeginType.AFTERTRAIN:
+					sysStateCode = SystemStateCode.AfterTrain_Begin;
+					break;
+				case BeginType.ABLUP:
+					sysStateCode = SystemStateCode.Ablup_Begin;
+					break;
+				case BeginType.TURNEND:
+					sysStateCode = SystemStateCode.Turnend_Begin;
+					break;
+				case BeginType.FIRST:
+					sysStateCode = SystemStateCode.First_Begin;
+					break;
+				case BeginType.TITLE:
+					sysStateCode = SystemStateCode.Title_Begin;
+					break;
+				//セット時に判定してるので、ここには来ないはず
+				//default:
+				//    throw new ExeEE("不適当なBEGIN呼び出し");
+			}
+			if (Program.DebugMode)
+			{
+				console.DebugClearTraceLog();
+				console.DebugAddTraceLog("BEGIN:" + begintype);
+			}
+			foreach (CalledFunction called in functionList)
+                if (called.CurrentLabel.hasPrivDynamicVar)
+                    called.CurrentLabel.Out();
+			functionList.Clear();
+			begintype = BeginType.NULL;
+		}
+
+		/// <summary>
+		/// システムによる強制的なBEGIN
+		/// </summary>
+		/// <param name="type"></param>
+		public void Begin(BeginType type)
+		{
+			begintype = type;
+			sysStateCode = SystemStateCode.Title_Begin;
+			Begin();
+		}
+
+		public LogicalLine GetCurrentReturnAddress
+		{
+			get
+			{
+                if (functionList.Count == currentMin)
+                    return null;
+				return functionList[functionList.Count - 1].ReturnAddress;
+			}
+		}
+
+        public LogicalLine GetReturnAddressSequensial(int curerntDepth)
+        {
+            if (functionList.Count == currentMin)
+                return null;
+            return functionList[functionList.Count - curerntDepth - 1].ReturnAddress;
+        }
+
+		public string Scope
+		{
+			get
+			{
+				//スクリプトの実行中処理からしか呼び出されないので、ここはない…はず
+				//if (functionList.Count == 0)
+				//{
+				//    throw new ExeEE("実行中の関数が存在しません");
+				//}
+				if (functionList.Count == 0)
+					return null;//1756 デバッグコマンドから呼び出されるようになったので
+				return functionList[functionList.Count - 1].FunctionName;
+			}
+		}
+
+		public void Return(Int64 ret)
+		{
+			if (IsFunctionMethod)
+			{
+				ReturnF(null);
+				return;
+			}
+			//sequential = false;//いずれにしろ順列ではない。
+			//呼び出し元は全部スクリプト処理
+			//if (functionList.Count == 0)
+			//{
+			//    throw new ExeEE("実行中の関数が存在しません");
+			//}
+			CalledFunction called = functionList[functionList.Count - 1];
+			if (called.IsJump)
+			{//JUMPした場合。即座にRETURN RESULTする。
+                if (called.TopLabel.hasPrivDynamicVar)
+                    called.TopLabel.Out();
+				functionList.Remove(called);
+				if (Program.DebugMode)
+					console.DebugRemoveTraceLog();
+				Return(ret);
+				return;
+			}
+			if (!called.IsEvent)
+			{
+                if (called.TopLabel.hasPrivDynamicVar)
+                    called.TopLabel.Out();
+                currentLine = null;
+            }
+			else
+			{
+                if (called.CurrentLabel.hasPrivDynamicVar)
+                    called.CurrentLabel.Out();
+				//#Singleフラグ付き関数で1が返された。
+				//1752 非0ではなく1と等価であることを見るように修正
+				//1756 全てを終了ではなく#PRIや#LATERのグループごとに修正
+                if (called.IsOnly)
+                    called.FinishEvent();
+				else if ((called.HasSingleFlag) && (ret == 1))
+					called.ShiftNextGroup();
+				else
+                    called.ShiftNext();//次の同名関数に進む。
+                currentLine = called.CurrentLabel;//関数の始点(@~~)へ移動。呼ぶべき関数が無ければnull
+                if (called.CurrentLabel != null)
+                {
+                    lineCount++;
+                    if (called.CurrentLabel.hasPrivDynamicVar)
+                        called.CurrentLabel.In();
+                }
+            }
+			if (Program.DebugMode)
+				console.DebugRemoveTraceLog();
+			//関数終了
+            if (currentLine == null)
+            {
+                currentLine = called.ReturnAddress;
+                functionList.RemoveAt(functionList.Count - 1);
+				if (currentLine == null)
+				{
+					//この時点でfunctionListは空のはず
+					//functionList.Clear();//全て終了。stateEndProcessに処理を返す
+					if (begintype != BeginType.NULL)//BEGIN XXが行なわれていれば
+					{
+						Begin();
+					}
+					return;
+				}
+                lineCount++;
+                //ShfitNextLine();
+                return;
+			}
+
+			if (Program.DebugMode)
+			{
+				FunctionLabelLine label = called.CurrentLabel;
+				console.DebugAddTraceLog("CALL :@" + label.LabelName + ":" + label.Position + "行目");
+			}
+			lineCount++;
+            //ShfitNextLine();
+		}
+
+		public void IntoFunction(CalledFunction call, UserDefinedFunctionArgument srcArgs, ExpressionMediator exm)
+		{
+
+			if (call.IsEvent)
+			{
+				foreach (CalledFunction called in functionList)
+				{
+					if (called.IsEvent)
+						throw new CodeEE("EVENT関数の解決前にCALLEVENT命令が行われました");
+				}
+			}
+			if (Program.DebugMode)
+			{
+				FunctionLabelLine label = call.CurrentLabel;
+				if (call.IsJump)
+					console.DebugAddTraceLog("JUMP :@" + label.LabelName + ":" + label.Position + "行目");
+				else
+					console.DebugAddTraceLog("CALL :@" + label.LabelName + ":" + label.Position + "行目");
+			}
+            if (srcArgs != null)
+            {
+                //引数の値を確定させる
+                srcArgs.SetTransporter(exm);
+                //プライベート変数更新
+                if (call.TopLabel.hasPrivDynamicVar)
+                    call.TopLabel.In();
+                //更新した変数へ引数を代入
+                for (int i = 0; i < call.TopLabel.Arg.Length; i++)
+                {
+                    if (srcArgs.Arguments[i] != null)
+                    {
+						if (call.TopLabel.Arg[i].Identifier.IsReference)
+							((ReferenceToken)(call.TopLabel.Arg[i].Identifier)).SetRef(srcArgs.TransporterRef[i]);
+                        else if (srcArgs.Arguments[i].GetOperandType() == typeof(Int64))
+                            call.TopLabel.Arg[i].SetValue(srcArgs.TransporterInt[i], exm);
+                        else
+                            call.TopLabel.Arg[i].SetValue(srcArgs.TransporterStr[i], exm);
+                    }
+                }
+            }
+            else//こっちに来るのはシステムからの呼び出し=引数は存在しない関数のみ ifネストの外に出していい気もしないでもないがはてさて
+            {
+                //プライベート変数更新
+                if (call.TopLabel.hasPrivDynamicVar)
+                    call.TopLabel.In();
+            }
+			functionList.Add(call);
+			//sequential = false;
+            currentLine = call.CurrentLabel;
+            lineCount++;
+            //ShfitNextLine();
+        }
+
+		#region userdifinedmethod
+		public bool IsFunctionMethod => functionList[currentMin].TopLabel.IsMethod;
+
+		public SingleTerm MethodReturnValue;
+
+		public void ReturnF(SingleTerm ret)
+		{
+			//読み込み時のチェック済みのはず
+			//if (!IsFunctionMethod)
+			//    throw new ExeEE("ReturnFと#FUNCTIONのチェックがおかしい");
+			//sequential = false;//いずれにしろ順列ではない。
+			//呼び出し元はRETURNFコマンドか関数終了時のみ
+			//if (functionList.Count == 0)
+			//    throw new ExeEE("実行中の関数が存在しません");
+			//非イベント呼び出しなので、これは起こりえない
+			//else if (functionList.Count != 1)
+			//    throw new ExeEE("関数が複数ある");
+			if (Program.DebugMode)
+			{
+				console.DebugRemoveTraceLog();
+			}
+			//OutはGetValue側で行う
+			//functionList[0].TopLabel.Out();
+            currentLine = functionList[functionList.Count - 1].ReturnAddress;
+            functionList.RemoveAt(functionList.Count - 1);
+            //nextLine = null;
+            MethodReturnValue = ret;
+		}
+
+		#endregion
+
+		bool isClone;
+        public bool IsClone { get => isClone;
+	        set { isClone = value; } }
+
+		// functionListのコピーを必要とする呼び出し元が無かったのでコピーしないことにする。
+		public ProcessState Clone()
+		{
+			ProcessState ret = new ProcessState(console);
+			ret.isClone = true;
+			//どうせ消すからコピー不要
+			//foreach (CalledFunction func in functionList)
+			//	ret.functionList.Add(func.Clone());
+			ret.currentLine = currentLine;
+            //ret.nextLine = this.nextLine;
+            //ret.sequential = this.sequential;
+			ret.sysStateCode = sysStateCode;
+			ret.begintype = begintype;
+			//ret.MethodReturnValue = this.MethodReturnValue;
+			return ret;
+
+		}
+		//public ProcessState CloneForFunctionMethod()
+		//{
+		//    ProcessState ret = new ProcessState(console);
+		//    ret.isClone = true;
+
+		//    //どうせ消すからコピー不要
+		//    //foreach (CalledFunction func in functionList)
+		//    //	ret.functionList.Add(func.Clone());
+		//    ret.currentLine = this.currentLine;
+		//    ret.nextLine = this.nextLine;
+		//    //ret.sequential = this.sequential;
+		//    ret.sysStateCode = this.sysStateCode;
+		//    ret.begintype = this.begintype;
+		//    //ret.MethodReturnValue = this.MethodReturnValue;
+		//    return ret;
+		//}
+	}
+}

+ 1015 - 0
NTERA/Game/GameProc/Process.SystemProc.cs

@@ -0,0 +1,1015 @@
+using System;
+using System.Collections.Generic;
+using System.Media;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.Sub;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera.GameProc
+{
+	internal sealed partial class Process
+	{
+		private string[] _trainName;
+		delegate void SystemProcess();
+
+	    readonly Dictionary<SystemStateCode, SystemProcess> _systemProcessDictionary = new Dictionary<SystemStateCode, SystemProcess>();
+		private void InitSystemProcess()
+		{
+			_comAble = new int[_trainName.Length];
+			_systemProcessDictionary.Add(SystemStateCode.Title_Begin, beginTitle);
+			_systemProcessDictionary.Add(SystemStateCode.Openning, endOpenning);
+
+			_systemProcessDictionary.Add(SystemStateCode.Train_Begin, beginTrain);
+			_systemProcessDictionary.Add(SystemStateCode.Train_CallEventTrain, endCallEventTrain);
+			_systemProcessDictionary.Add(SystemStateCode.Train_CallShowStatus, endCallShowStatus);
+			_systemProcessDictionary.Add(SystemStateCode.Train_CallComAbleXX, endCallComAbleXX);
+			_systemProcessDictionary.Add(SystemStateCode.Train_CallShowUserCom, endCallShowUserCom);
+			_systemProcessDictionary.Add(SystemStateCode.Train_WaitInput, trainWaitInput);
+			_systemProcessDictionary.Add(SystemStateCode.Train_CallEventCom, endEventCom);
+			_systemProcessDictionary.Add(SystemStateCode.Train_CallComXX, endCallComXX);
+			_systemProcessDictionary.Add(SystemStateCode.Train_CallSourceCheck, endCallSourceCheck);
+			_systemProcessDictionary.Add(SystemStateCode.Train_CallEventComEnd, endCallEventComEnd); ;
+			_systemProcessDictionary.Add(SystemStateCode.Train_DoTrain, doTrain);
+
+			_systemProcessDictionary.Add(SystemStateCode.AfterTrain_Begin, beginAfterTrain);
+
+			_systemProcessDictionary.Add(SystemStateCode.Ablup_Begin, beginAblup);
+			_systemProcessDictionary.Add(SystemStateCode.Ablup_CallShowJuel, endCallShowJuel);
+			_systemProcessDictionary.Add(SystemStateCode.Ablup_CallShowAblupSelect, endCallShowAblupSelect);
+			_systemProcessDictionary.Add(SystemStateCode.Ablup_WaitInput, ablupWaitInput);
+			_systemProcessDictionary.Add(SystemStateCode.Ablup_CallAblupXX, endCallAblupXX);
+
+			_systemProcessDictionary.Add(SystemStateCode.Turnend_Begin, beginTurnend);
+
+			_systemProcessDictionary.Add(SystemStateCode.Shop_Begin, beginShop);
+			_systemProcessDictionary.Add(SystemStateCode.Shop_CallEventShop, endCallEventShop);
+			_systemProcessDictionary.Add(SystemStateCode.Shop_CallShowShop, endCallShowShop);
+			_systemProcessDictionary.Add(SystemStateCode.Shop_WaitInput, shopWaitInput);
+			_systemProcessDictionary.Add(SystemStateCode.Shop_CallEventBuy, endCallEventBuy);
+
+			_systemProcessDictionary.Add(SystemStateCode.SaveGame_Begin, beginSaveGame);
+			_systemProcessDictionary.Add(SystemStateCode.SaveGame_WaitInput, saveGameWaitInput);
+			_systemProcessDictionary.Add(SystemStateCode.SaveGame_WaitInputOverwrite, saveGameWaitInputOverwrite);
+			_systemProcessDictionary.Add(SystemStateCode.SaveGame_CallSaveInfo, endCallSaveInfo);
+			_systemProcessDictionary.Add(SystemStateCode.LoadGame_Begin, beginLoadGame);
+			_systemProcessDictionary.Add(SystemStateCode.LoadGame_WaitInput, loadGameWaitInput);
+			_systemProcessDictionary.Add(SystemStateCode.LoadGameOpenning_Begin, beginLoadGameOpening);
+			_systemProcessDictionary.Add(SystemStateCode.LoadGameOpenning_WaitInput, loadGameWaitInput);
+
+			//stateEndProcessDictionary.Add(ProgramState.AutoSave_Begin, new stateEndProcess(this.beginAutoSave));
+			_systemProcessDictionary.Add(SystemStateCode.AutoSave_CallSaveInfo, endAutoSaveCallSaveInfo);
+			_systemProcessDictionary.Add(SystemStateCode.AutoSave_CallUniqueAutosave, endAutoSave);
+
+			_systemProcessDictionary.Add(SystemStateCode.LoadData_DataLoaded, beginDataLoaded);
+			_systemProcessDictionary.Add(SystemStateCode.LoadData_CallSystemLoad, endSystemLoad);
+			_systemProcessDictionary.Add(SystemStateCode.LoadData_CallEventLoad, endEventLoad);
+
+			_systemProcessDictionary.Add(SystemStateCode.Openning_TitleLoadgame, endTitleLoadgame);
+
+			_systemProcessDictionary.Add(SystemStateCode.System_Reloaderb, endReloaderb);
+			_systemProcessDictionary.Add(SystemStateCode.First_Begin, beginFirst);
+
+
+			_systemProcessDictionary.Add(SystemStateCode.Normal, endNormal);
+		}
+
+
+
+		Int64 _systemResult;
+		int _lastCalledComable = -1;
+		int _lastAddCom = -1;
+		//(Train.csv中の値・定義されていなければ-1) == comAble[(表示されている値)];
+		int[] _comAble;//
+
+
+		private void RunSystemProc()
+		{
+			//スクリプト実行中にここには来ないはず
+			//if (!state.ScriptEnd)
+			//    throw new ExeEE("不正な呼び出し");
+
+			//ない物を渡す処理は現状ない
+			//if (systemProcessDictionary.ContainsKey(state.SystemState))
+			_systemProcessDictionary[state.SystemState]();
+			//else
+			//    throw new ExeEE("未定義の状態");
+
+		}
+
+		void SetWait()
+		{
+			console.ReadAnyKey();
+		}
+
+		void SetWaitInput()
+		{
+			InputRequest req = new InputRequest();
+			req.InputType = InputType.IntValue;
+			req.IsSystemInput = true;
+			console.WaitInput(req);
+		}
+
+
+		private bool CallFunction(string functionName, bool force, bool isEvent)
+		{
+			CalledFunction call = null;
+			if (isEvent)
+				call = CalledFunction.CallEventFunction(this, functionName, null);
+			else
+				call = CalledFunction.CallFunction(this, functionName, null);
+			if (call == null)
+				if (!force)
+					return false;
+				else
+					throw new CodeEE("関数\"@" + functionName + "\"が見つかりません");
+			//そもそも非イベント関数では関数1個分しか与えないので条件を満たすわけがない
+			//if ((!isEvent) && (call.Count > 1))
+			//    throw new ExeEE("イベント関数でない関数\"@" + functionName + "\"の候補が複数ある");
+			state.IntoFunction(call, null, null);
+			return true;
+		}
+
+		//CheckState()から呼ばれる関数群。ScriptEndに達したときの処理。
+
+		void beginTitle()
+		{
+			//連続調教コマンド処理中の状態が持ち越されていたらここで消しておく
+			if (isCTrain)
+				if (ClearCommands())
+					return;
+			skipPrint = false;
+			console.ResetStyle();
+			deleteAllPrevState();
+			if (Program.AnalysisMode)
+			{
+				console.PrintSystemLine("ファイル解析終了:Analysis.logに出力します");
+				console.OutputLog(Program.ExeDir + "Analysis.log");
+				console.noOutputLog = true;
+				console.PrintSystemLine("エンターキーもしくはクリックで終了します");
+				SystemSounds.Asterisk.Play();
+				console.ThrowTitleError(false);
+				return;
+			}
+			if ((!noError) && (!Config.CompatiErrorLine))
+			{
+				console.PrintSystemLine("ERBコードに解釈不可能な行があるためEmueraを終了します");
+				console.PrintSystemLine("※互換性オプション「" + Config.GetConfigName(ConfigCode.CompatiErrorLine) + "」により強制的に動作させることができます");
+				console.PrintSystemLine("emuera.logにログを出力します");
+				console.OutputLog(Program.ExeDir + "emuera.log");
+				console.noOutputLog = true;
+				console.PrintSystemLine("エンターキーもしくはクリックで終了します");
+				//System.Media.SystemSounds.Asterisk.Play();
+				console.ThrowTitleError(true);
+				return;
+			}
+			if (CallFunction("SYSTEM_TITLE", false, false))
+			{//独自定義
+				state.SystemState = SystemStateCode.Normal;
+				return;
+			}
+			//標準のタイトル画面
+			console.PrintBar();
+			console.NewLine();
+			console.Alignment = DisplayLineAlignment.CENTER;
+			console.PrintSingleLine(gamebase.ScriptTitle);
+			if (gamebase.ScriptVersion != 0)
+				console.PrintSingleLine(gamebase.ScriptVersionText);
+			console.PrintSingleLine(gamebase.ScriptAutherName);
+			console.PrintSingleLine("(" + gamebase.ScriptYear + ")");
+			console.NewLine();
+			console.PrintSingleLine(gamebase.ScriptDetail);
+			console.Alignment = DisplayLineAlignment.LEFT;
+
+			console.PrintBar();
+			console.NewLine();
+			console.PrintSingleLine("[0] " + Config.TitleMenuString0);
+			console.PrintSingleLine("[1] " + Config.TitleMenuString1);
+			openingInput();
+		}
+
+		void openingInput()
+		{
+			SetWaitInput();
+			state.SystemState = SystemStateCode.Openning;
+		}
+
+		void endOpenning()
+		{
+			if (_systemResult == 0)
+			{//[0] 最初からはじめる
+				vEvaluator.ResetData();
+				//vEvaluator.AddCharacter(0, false);
+				vEvaluator.AddCharacterFromCsvNo(0);
+				if (gamebase.DefaultCharacter > 0)
+					//vEvaluator.AddCharacter(gamebase.DefaultCharacter, false);
+					vEvaluator.AddCharacterFromCsvNo(gamebase.DefaultCharacter);
+				console.PrintBar();
+				console.NewLine();
+				beginFirst();
+			}
+			else if (_systemResult == 1)
+			{
+				if (CallFunction("TITLE_LOADGAME", false, false))
+				{//独自定義
+					state.SystemState = SystemStateCode.Openning_TitleLoadgame;
+				}
+				else
+				{//標準のLOADGAME
+					beginLoadGameOpening();
+				}
+			}
+			else//入力が正しくないならもう一回選択肢を書き直し、正しい選択を要求する。
+			{//RESUELASTLINEと同様の処理を行うように変更
+				console.deleteLine(1);
+				console.PrintTemporaryLine("Invalid value");
+				console.updatedGeneration = true;
+				openingInput();
+				//beginTitle();
+			}
+
+		}
+
+		void beginFirst()
+		{
+			state.SystemState = SystemStateCode.Normal;
+			//連続調教コマンド処理中の状態が持ち越されていたらここで消しておく
+			if (isCTrain)
+				if (ClearCommands())
+					return;
+			skipPrint = false;
+			CallFunction("EVENTFIRST", true, true);
+		}
+
+		void endTitleLoadgame()
+		{
+			beginTitle();
+		}
+
+		void beginTrain()
+		{
+			vEvaluator.UpdateInBeginTrain();
+			state.SystemState = SystemStateCode.Train_CallEventTrain;
+			//EVENTTRAINを呼び出してTrain_CallEventTrainへ移行。
+			if (!CallFunction("EVENTTRAIN", false, true))
+			{
+				//存在しなければスキップしてTrain_CallEventTrainが終わったことにする。
+				endCallEventTrain();
+			}
+		}
+
+		List<Int64> coms = new List<long>();
+		bool isCTrain;
+		int count;
+		bool skipPrint;
+		public bool SkipPrint { get => skipPrint;
+			set { skipPrint = value; } }
+		void endCallEventTrain()
+		{
+			if (vEvaluator.NEXTCOM >= 0)
+			{//NEXTCOMの処理
+				state.SystemState = SystemStateCode.Train_CallEventCom;
+				vEvaluator.SELECTCOM = vEvaluator.NEXTCOM;
+				vEvaluator.NEXTCOM = 0;
+				//-1ではなく0を代入するのでERB側で変更しない限り無限にはまることになるがeramakerからの仕様である。
+				callEventCom();
+			}
+			else
+			{
+				//if (!isCTrain)
+				//{
+				//SHOW_STATUSを呼び出してTrain_CallShowStatusへ移行。
+				if (isCTrain)
+					skipPrint = true;
+				CallFunction("SHOW_STATUS", true, false);
+				state.SystemState = SystemStateCode.Train_CallShowStatus;
+				//}
+				//else
+				//{
+				//連続調教モードならCOMABLE処理へ
+				//	endCallShowStatus();
+				//}
+			}
+		}
+
+		void endCallShowStatus()
+		{
+			//SHOW_STATUSが終わったらComAbleXXの呼び出し状態をリセットしてTrain_CallComAbleXXへ移行。
+			state.SystemState = SystemStateCode.Train_CallComAbleXX;
+			_lastCalledComable = -1;
+			_lastAddCom = -1;
+			printComCount = 0;
+			for (int i = 0; i < _comAble.Length; i++)
+				_comAble[i] = -1;
+			endCallComAbleXX();
+		}
+
+		string getTrainComString(int trainCode, int comNo)
+		{
+			string trainName = Translation.translate(_trainName[trainCode], "Train", true);
+			return string.Format("{0}[{1,3}]", trainName, comNo);
+		}
+
+		int printComCount;
+		void endCallComAbleXX()
+		{
+			//選択肢追加。RESULTが0の場合は選択肢の番号のみ増やして追加はしない。
+			if ((_lastCalledComable >= 0) && (_trainName[_lastCalledComable] != null))
+			{
+				_lastAddCom++;
+				if (vEvaluator.RESULT != 0)
+				{
+					_comAble[_lastAddCom] = _lastCalledComable;
+					if (!isCTrain)
+					{
+						console.PrintC(getTrainComString(_lastCalledComable, _lastAddCom), true);
+						printComCount++;
+						if ((Config.PrintCPerLine > 0) && (printComCount % Config.PrintCPerLine == 0))
+							console.PrintFlush(false);
+					}
+					console.RefreshStrings(false);
+				}
+			}
+			//ComAbleXXの呼び出し。train.csvに定義されていないものはスキップ、ComAbleXXが見つからなければREUTRN 1と同様に扱う。
+			while (++_lastCalledComable < _trainName.Length)
+			{
+				if (_trainName[_lastCalledComable] == null)
+					continue;
+				string comName = string.Format("COM_ABLE{0}", _lastCalledComable);
+				if (!CallFunction(comName, false, false))
+				{
+					_lastAddCom++;
+					if (Config.ComAbleDefault == 0)
+						continue;
+					_comAble[_lastAddCom] = _lastCalledComable;
+					if (!isCTrain)
+					{
+						console.PrintC(getTrainComString(_lastCalledComable, _lastAddCom), true);
+						printComCount++;
+						if ((Config.PrintCPerLine > 0) && (printComCount % Config.PrintCPerLine == 0))
+							console.PrintFlush(false);
+					}
+					continue;
+				}
+				console.RefreshStrings(false);
+				return;
+			}
+			//全部検索したら終了し、SHOW_USERCOMを呼び出す。
+			if (_lastCalledComable >= _trainName.Length)
+			{
+				state.SystemState = SystemStateCode.Train_CallShowUserCom;
+				//if (!isCTrain)
+				//{
+				console.PrintFlush(false);
+				console.RefreshStrings(false);
+				CallFunction("SHOW_USERCOM", true, false);
+				//}
+				//else
+				//	endCallShowUserCom();
+			}
+		}
+
+		void endCallShowUserCom()
+		{
+			if (skipPrint)
+				skipPrint = false;
+			vEvaluator.UpdateAfterShowUsercom();
+			if (!isCTrain)
+			{
+				//数値入力待ち状態にしてTrain_WaitInputへ移行。
+				SetWaitInput();
+
+				state.SystemState = SystemStateCode.Train_WaitInput;
+			}
+			else
+			{
+				if (count < coms.Count)
+				{
+					_systemResult = coms[count];
+					count++;
+					trainWaitInput();
+				}
+			}
+		}
+
+		void trainWaitInput()
+		{
+			int selectCom = -1;
+			if (!isCTrain)
+			{
+				if ((_systemResult >= 0) && (_systemResult < _comAble.Length))
+					selectCom = _comAble[_systemResult];
+			}
+			else
+			{
+				for (int i = 0; i < _comAble.Length; i++)
+				{
+					if (_comAble[i] == _systemResult)
+						selectCom = (int)_systemResult;
+				}
+				console.PrintSingleLine(string.Format("<Executed command:{0}/{1}>", count, coms.Count));
+			}
+			//TrainNameが定義されていて使用可能(COMABLEが非0を返した)である
+			if (selectCom >= 0)
+			{
+				vEvaluator.SELECTCOM = selectCom;
+				callEventCom();
+			}
+			else
+			{//されていない。
+				if (isCTrain)
+					console.PrintSingleLine("Unable to execute command");
+				vEvaluator.RESULT = _systemResult;
+				state.SystemState = SystemStateCode.Train_CallEventComEnd;
+				CallFunction("USERCOM", true, false);
+				//COM中の必要なことは全部USERCOM内でやる。
+			}
+		}
+
+		private Int64 doTrainSelectCom = -1;
+		void doTrain()
+		{
+			vEvaluator.UpdateAfterShowUsercom();
+			vEvaluator.SELECTCOM = doTrainSelectCom;
+			callEventCom();
+		}
+
+		void callEventCom()
+		{
+			vEvaluator.UpdateAfterInputCom();
+			state.SystemState = SystemStateCode.Train_CallEventCom;
+			if (!CallFunction("EVENTCOM", false, true))
+				endEventCom();
+		}
+
+		void endEventCom()
+		{
+			long selectCom = vEvaluator.SELECTCOM;
+			string comName = string.Format("COM{0}", selectCom);
+			state.SystemState = SystemStateCode.Train_CallComXX;
+			CallFunction(comName, true, false);
+		}
+
+		void endCallComXX()
+		{
+			//実行に失敗した
+			if (vEvaluator.RESULT == 0)
+			{
+				//Com終了。
+				endCallEventComEnd();
+			}
+			else
+			{//成功したならSOURCE_CHECKへ移行。
+				state.SystemState = SystemStateCode.Train_CallSourceCheck;
+				CallFunction("SOURCE_CHECK", true, false);
+			}
+		}
+
+		void endCallSourceCheck()
+		{
+			//SOURCEはここでリセット
+			vEvaluator.UpdateAfterSourceCheck();
+			//EVENTCOMENDを呼び出してTrain_CallEventComEndへ移行。
+			state.SystemState = SystemStateCode.Train_CallEventComEnd;
+			//EVENTCOMENDが存在しない、またはEVENTCOMEND内でWAIT系命令が行われない場合、EVENTCOMEND後にWAITを追加する。
+			NeedWaitToEventComEnd = true;
+			if (!CallFunction("EVENTCOMEND", false, true))
+			{
+				//見つからないならスキップしてTrain_CallEventComEndが終了したとみなす。
+				endCallEventComEnd();
+			}
+		}
+		public bool NeedWaitToEventComEnd;
+		bool needCheck = true;
+		void endCallEventComEnd()
+		{
+			if (console.LastLineIsTemporary && !isCTrain && needCheck)
+			{
+                if (console.LastLineIsEmpty)
+                {
+                    console.deleteLine(2);
+                    console.PrintTemporaryLine("Invalid value");
+                }
+				console.updatedGeneration = true;
+				endCallShowUserCom();
+			}
+			else
+			{
+				if (isCTrain && count == coms.Count)
+				{
+					isCTrain = false;
+					skipPrint = false;
+					coms.Clear();
+					count = 0;
+					if (CallFunction("CALLTRAINEND", false, false))
+					{
+						needCheck = false;
+						return;
+					}
+				}
+				needCheck = true;
+				////1.701	ここでWAITは不要だった。
+				////setWait();
+				//1.703 やはり必要な場合もあった
+				if (NeedWaitToEventComEnd)
+					SetWait();
+				NeedWaitToEventComEnd = false;
+				//SHOW_STATUSからやり直す。
+				//処理はTrain_CallEventTrainと同じ。
+				endCallEventTrain();
+			}
+		}
+
+		void beginAfterTrain()
+		{
+			//連続調教モード中にここに来る場合があるので、ここで解除
+			if (isCTrain)
+				if (ClearCommands())
+					return;
+			skipPrint = false;
+			state.SystemState = SystemStateCode.Normal;
+			//EVENTENDを呼び出す。exe側が状態を把握する必要が無くなるのでNormalへ移行。
+			CallFunction("EVENTEND", true, true);
+		}
+
+		void beginAblup()
+		{
+			//連続調教コマンド処理中の状態が持ち越されていたらここで消しておく
+			if (isCTrain)
+				if (ClearCommands())
+					return;
+			skipPrint = false;
+			state.SystemState = SystemStateCode.Ablup_CallShowJuel;
+			//SHOW_JUELを呼び出しAblup_CallShowJuelへ移行。
+			CallFunction("SHOW_JUEL", true, false);
+		}
+
+		void endCallShowJuel()
+		{
+			state.SystemState = SystemStateCode.Ablup_CallShowAblupSelect;
+			//SHOW_ABLUP_SELECTを呼び出しAblup_CallAblupSelectへ移行。
+			CallFunction("SHOW_ABLUP_SELECT", true, false);
+		}
+
+		void endCallShowAblupSelect()
+		{
+			//数値入力待ち状態にしてAblup_WaitInputへ移行。
+			SetWaitInput();
+			state.SystemState = SystemStateCode.Ablup_WaitInput;
+		}
+
+		void ablupWaitInput()
+		{
+			//定義されていなくても100未満ならABLUPが呼ばれ、USERABLUPは呼ばれない。そうしないと[99]反発刻印とかが出来ない。
+			if ((_systemResult >= 0) && (_systemResult < 100))
+			{
+				state.SystemState = SystemStateCode.Ablup_CallAblupXX;
+				string ablName = string.Format("ABLUP{0}", _systemResult);
+				if (!CallFunction(ablName, false, false))
+				{
+					//見つからなければ終了
+					console.deleteLine(1);
+					console.PrintTemporaryLine("Invalid value");
+					console.updatedGeneration = true;
+					endCallShowAblupSelect();
+				}
+			}
+			else
+			{
+				vEvaluator.RESULT = _systemResult;
+				state.SystemState = SystemStateCode.Ablup_CallAblupXX;
+				CallFunction("USERABLUP", true, false);
+			}
+		}
+
+		void endCallAblupXX()
+		{
+			if (console.LastLineIsTemporary)
+			{
+                if (console.LastLineIsEmpty)
+                {
+                    console.deleteLine(2);
+                    console.PrintTemporaryLine("Invalid value");
+                }
+				console.updatedGeneration = true;
+				endCallShowAblupSelect();
+			}
+			else
+				beginAblup();
+		}
+
+		void beginTurnend()
+		{
+			//連続調教コマンド処理中の状態が持ち越されていたらここで消しておく
+			if (isCTrain)
+				if (ClearCommands())
+					return;
+			skipPrint = false;
+			//EVENTTURNENDを呼び出しNormalへ移行
+			CallFunction("EVENTTURNEND", true, true);
+			state.SystemState = SystemStateCode.Normal;
+		}
+
+		void beginShop()
+		{
+			//連続調教コマンド処理中の状態が持ち越されていたらここで消しておく
+			if (isCTrain)
+				if (ClearCommands())
+					return;
+			skipPrint = false;
+			state.SystemState = SystemStateCode.Shop_CallEventShop;
+			//EVENTSHOPを呼び出してShop_CallEventShopへ移行。
+			if (!CallFunction("EVENTSHOP", false, true))
+			{
+				//存在しなければスキップしてShop_CallEventShopが終わったことにする。
+				endCallEventShop();
+			}
+		}
+
+		void endCallEventShop()
+		{
+			saveTarget = -1;
+			if (Config.AutoSave && state.calledWhenNormal)
+				beginAutoSave();
+			else
+			{
+				state.SystemState = SystemStateCode.AutoSave_Skipped;
+				endAutoSaveCallSaveInfo();
+			}
+		}
+
+		void beginAutoSave()
+		{
+			if (CallFunction("SYSTEM_AUTOSAVE", false, false))
+			{//@SYSTEM_AUTOSAVEが存在するならそれを使う。
+				state.SystemState = SystemStateCode.AutoSave_CallUniqueAutosave;
+				return;
+			}
+			saveTarget = AutoSaveIndex;
+			vEvaluator.SAVEDATA_TEXT = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") + " ";
+			state.SystemState = SystemStateCode.AutoSave_CallSaveInfo;
+			if (!CallFunction("SAVEINFO", false, false))
+				endAutoSaveCallSaveInfo();//存在しなければスキップ
+		}
+
+		void endAutoSaveCallSaveInfo()
+		{
+			if (saveTarget == AutoSaveIndex)
+			{
+				if (!vEvaluator.SaveTo(saveTarget, vEvaluator.SAVEDATA_TEXT))
+				{
+					console.PrintError("オートセーブ中に予期しないエラーが発生しました");
+					console.PrintError("オートセーブをスキップします");
+					console.ReadAnyKey();
+				}
+			}
+			endAutoSave();
+		}
+
+		void endAutoSave()
+		{
+			if (state.isBegun)
+			{
+				state.Begin();
+				return;
+			}
+			state.SystemState = SystemStateCode.Shop_CallShowShop;
+			//SHOW_SHOPを呼び出しShop_CallShowShopへ移行
+			CallFunction("SHOW_SHOP", true, false);
+		}
+
+		void endCallShowShop()
+		{
+			//数値入力待ち状態にしてShop_WaitInputへ移行。
+			SetWaitInput();
+			state.SystemState = SystemStateCode.Shop_WaitInput;
+		}
+
+		//PRINT_SHOPITEMとは独立している。
+		//BOUGHTが100以上のアイテムが有り、ITEMSALESがTRUEだとしても強制的に@USERSHOP行き。
+		void shopWaitInput()
+		{
+			if ((_systemResult >= 0) && (_systemResult < Config.MaxShopItem))
+			{
+				if (vEvaluator.ItemSales(_systemResult))
+				{
+					if (vEvaluator.BuyItem(_systemResult))
+					{
+						state.SystemState = SystemStateCode.Shop_CallEventBuy;
+						//EVENTBUYを呼び出しShop_CallEventBuyへ移行
+						if (!CallFunction("EVENTBUY", false, true))
+							endCallEventBuy();
+						return;
+					}
+
+					//console.Print("お金が足りません。");
+					//console.NewLine();
+					console.deleteLine(1);
+					console.PrintTemporaryLine("お金が足りません。");
+				}
+				else
+				{
+					//console.Print("売っていません。");
+					//console.NewLine();
+					console.deleteLine(1);
+					console.PrintTemporaryLine("売っていません。");
+				}
+				//購入に失敗した場合、endCallEventShop()に戻す。
+				//endCallEventShop();
+				endCallShowShop();
+			}
+			else
+			{
+				//RESULTを更新
+				vEvaluator.RESULT = _systemResult;
+
+				//USERSHOPを呼び出しShop_CallEventBuyへ移行
+				CallFunction("USERSHOP", true, false);
+				state.SystemState = SystemStateCode.Shop_CallEventBuy;
+			}
+		}
+
+		void endCallEventBuy()
+		{
+			if (console.LastLineIsTemporary)
+			{
+                if (console.LastLineIsEmpty)
+                {
+                    console.deleteLine(2);
+                    console.PrintTemporaryLine("Invalid value");
+                }
+				console.updatedGeneration = true;
+				endCallShowShop();
+			}
+			else
+			{
+				//最初に戻る
+				endAutoSave();
+			}
+		}
+
+
+		void beginDataLoaded()
+		{
+			state.SystemState = SystemStateCode.LoadData_CallSystemLoad;
+			
+			if (!CallFunction("SYSTEM_LOADEND", false, false))
+				endSystemLoad();//存在しなければスキップ
+		}
+		void endSystemLoad()
+		{
+			state.SystemState = SystemStateCode.LoadData_CallEventLoad;
+			//EVENTLOADを呼び出してLoadData_CallEventLoadへ移行。
+			if (!CallFunction("EVENTLOAD", false, true))
+			{
+				//存在しなければスキップしてTrain_CallEventTrainが終わったことにする。
+				endAutoSave();
+			}
+		}
+
+		void endEventLoad()
+		{
+			//@EVENTLOAD中にBEGIN命令が行われればここには来ない。
+			//ここに来たらBEGIN SHOP扱い。オートセーブはしない。
+			endAutoSave();
+		}
+
+		void beginSaveGame()
+		{
+			console.PrintSingleLine("Where do you want to save?");
+			state.SystemState = SystemStateCode.SaveGame_Begin;
+			printSaveDataText();
+		}
+
+		void beginLoadGame()
+		{
+			console.PrintSingleLine("What do you want to load?");
+			state.SystemState = SystemStateCode.LoadGame_Begin;
+			printSaveDataText();
+		}
+
+		void beginLoadGameOpening()
+		{
+			console.PrintSingleLine("Which save do you load?");
+			state.SystemState = SystemStateCode.LoadGameOpenning_Begin;
+			printSaveDataText();
+		}
+
+		bool[] dataIsAvailable = new bool[21];
+		bool isFirstTime = true;
+		const int AutoSaveIndex = 99;
+		int page;
+		void printSaveDataText()
+		{
+			if (isFirstTime)
+			{
+				isFirstTime = false;
+				dataIsAvailable = new bool[Config.SaveDataNos + 1];
+			}
+			int dataNo = 0;
+			for (int i = 0; i < page; i++)
+			{
+				console.PrintFlush(false);
+				console.Print(string.Format("[{0, 2}] Display slots {0, 2}~{1, 2}", i * 20, i * 20 + 19));
+			}
+			for (int i = 0; i < 20; i++)
+			{
+				dataNo = page * 20 + i;
+				if (dataNo == dataIsAvailable.Length - 1)
+					break;
+				dataIsAvailable[dataNo] = false;
+				console.PrintFlush(false);
+				console.Print(string.Format("[{0, 2}] ", dataNo));
+				if (!writeSavedataTextFrom(dataNo))
+					continue;
+				dataIsAvailable[dataNo] = true;
+			}
+			for (int i = page; i < ((dataIsAvailable.Length - 2) / 20); i++)
+			{
+				console.PrintFlush(false);
+				console.Print(string.Format("[{0, 2}] Display slots {0, 2}~{1, 2}", (i + 1) * 20, (i + 1) * 20 + 19));
+			}
+			//オートセーブの処理は別途切り出し(表示処理の都合上)
+			dataIsAvailable[dataIsAvailable.Length - 1] = false;
+			if (state.SystemState != SystemStateCode.SaveGame_Begin)
+			{
+				dataNo = AutoSaveIndex;
+				console.PrintFlush(false);
+				console.Print(string.Format("[{0, 2}] ", dataNo));
+				if (writeSavedataTextFrom(dataNo))
+					dataIsAvailable[dataIsAvailable.Length - 1] = true;
+			}
+			console.RefreshStrings(false);
+			//描画全部終わり
+			console.PrintSingleLine("[100] Return");
+			SetWaitInput();
+			if (state.SystemState == SystemStateCode.SaveGame_Begin)
+				state.SystemState = SystemStateCode.SaveGame_WaitInput;
+			else if (state.SystemState == SystemStateCode.LoadGame_Begin)
+				state.SystemState = SystemStateCode.LoadGame_WaitInput;
+			else// if (state.SystemState == SystemStateCode.LoadGameOpenning_Begin)
+				state.SystemState = SystemStateCode.LoadGameOpenning_WaitInput;
+			//きちんと処理されてるので、ここには来ない
+			//else
+			//    throw new ExeEE("異常な状態");
+		}
+
+		int saveTarget = -1;
+		void saveGameWaitInput()
+		{
+			if (_systemResult == 100)
+			{
+				//キャンセルなら直前の状態を呼び戻す
+				loadPrevState();
+				return;
+			}
+
+			if (((int)_systemResult / 20) != page && _systemResult != AutoSaveIndex && (_systemResult >= 0 && _systemResult < dataIsAvailable.Length - 1))
+			{
+				page = (int)_systemResult / 20;
+				state.SystemState = SystemStateCode.SaveGame_Begin;
+				printSaveDataText();
+				return;
+			}
+			bool available = false;
+			if ((_systemResult >= 0) && (_systemResult < dataIsAvailable.Length - 1))
+				available = dataIsAvailable[_systemResult];
+			else
+			{//入力しなおし
+				console.deleteLine(1);
+				console.PrintTemporaryLine("Invalid value");
+				console.updatedGeneration = true;
+				SetWaitInput();
+				return;
+			}
+			saveTarget = (int)_systemResult;
+			//既存データがあるなら選択肢を表示してSaveGame_WaitInputOverwriteへ移行。
+			if (available)
+			{
+				console.PrintSingleLine("Save already exists. Overwrite?");
+				console.PrintC("[0] Yes", false);
+				console.PrintC("[1] No", false);
+				SetWaitInput();
+				state.SystemState = SystemStateCode.SaveGame_WaitInputOverwrite;
+				return;
+			}
+			//既存データがないなら「はい」を選んだことにして直接ジャンプ
+			_systemResult = 0;
+			saveGameWaitInputOverwrite();
+		}
+
+		void saveGameWaitInputOverwrite()
+		{
+			if (_systemResult == 1)//いいえ
+			{
+				beginSaveGame();
+				return;
+			}
+
+			if (_systemResult != 0)//「はい」でもない
+			{//入力しなおし
+				console.deleteLine(1);
+				console.PrintTemporaryLine("Invalid value");
+				console.updatedGeneration = true;
+				SetWaitInput();
+				return;
+			}
+			vEvaluator.SAVEDATA_TEXT = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") + " ";
+			state.SystemState = SystemStateCode.SaveGame_CallSaveInfo;
+			if (!CallFunction("SAVEINFO", false, false))
+				endCallSaveInfo();//存在しなければスキップ
+		}
+
+		void endCallSaveInfo()
+		{
+			if (!vEvaluator.SaveTo(saveTarget, vEvaluator.SAVEDATA_TEXT))
+			{
+				console.PrintError("Unexpected error while saving occured");
+				console.ReadAnyKey();
+			}
+			loadPrevState();
+		}
+
+		void loadGameWaitInput()
+		{
+			if (_systemResult == 100)
+			{//キャンセルなら
+				//オープニングならオープニングへ戻る
+				if (state.SystemState == SystemStateCode.LoadGameOpenning_WaitInput)
+				{
+					beginTitle();
+					return;
+				}
+				//それ以外から来たなら直前の状態を呼び戻す
+				loadPrevState();
+				return;
+			}
+
+			if (((int)_systemResult / 20) != page && _systemResult != AutoSaveIndex && (_systemResult >= 0 && _systemResult < dataIsAvailable.Length - 1))
+			{
+				page = (int)_systemResult / 20;
+				if (state.SystemState == SystemStateCode.LoadGameOpenning_WaitInput)
+					state.SystemState = SystemStateCode.LoadGameOpenning_Begin;
+				else
+					state.SystemState = SystemStateCode.LoadGame_Begin;
+				printSaveDataText();
+				return;
+			}
+			bool available = false;
+			if ((_systemResult >= 0) && (_systemResult < dataIsAvailable.Length - 1))
+				available = dataIsAvailable[_systemResult];
+			else if (_systemResult == AutoSaveIndex)
+				available = dataIsAvailable[dataIsAvailable.Length - 1];
+			else
+			{//入力しなおし
+				console.deleteLine(1);
+				console.PrintTemporaryLine("Invalid value");
+				console.updatedGeneration = true;
+				SetWaitInput();
+				return;
+			}
+			if (!available)
+			{
+				console.PrintSingleLine(_systemResult.ToString());
+				console.PrintError("No data found");
+				if (state.SystemState == SystemStateCode.LoadGameOpenning_WaitInput)
+				{
+					beginLoadGameOpening();
+					return;
+				}
+				beginLoadGame();
+				return;
+			}
+
+			if (!vEvaluator.LoadFrom((int)_systemResult))
+				throw new ExeEE("Unexpected error while loading save");
+			deletePrevState();
+			beginDataLoaded();
+		}
+
+
+		void endNormal()
+		{
+			throw new CodeEE("Script execution terminated");
+		}
+
+		void endReloaderb()
+		{
+			loadPrevState();
+			console.ReloadErbFinished();
+		}
+
+		private bool writeSavedataTextFrom(int saveIndex)
+		{
+			EraDataResult result = vEvaluator.CheckData(saveIndex, EraSaveFileType.Normal);
+			console.Print(result.DataMes);
+			console.NewLine();
+			return result.State == EraDataState.OK;
+		}
+
+		//1808 vEvaluator.SaveTo()などに移動
+		//private bool loadFrom(int dataIndex)
+		//private bool saveTo(int saveIndex, string saveText)
+		//private string getSaveDataPath(int index)
+	}
+
+}

+ 487 - 0
NTERA/Game/GameProc/Process.cs

@@ -0,0 +1,487 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Windows.Forms;
+using MinorShift.Emuera.Content;
+using MinorShift.Emuera.GameData;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.GameData.Function;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.GameProc.Function;
+using MinorShift.Emuera.Sub;
+using MinorShift._Library;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera.GameProc
+{
+	internal sealed partial class Process
+	{
+		public Process(IConsole view)
+		{
+			console = view;
+		}
+
+        public LogicalLine getCurrentLine => state.CurrentLine;
+
+		/// <summary>
+		/// @~~と$~~を集めたもの。CALL命令などで使う
+		/// 実行順序はLogicalLine自身が保持する。
+		/// </summary>
+		LabelDictionary labelDic;
+		public LabelDictionary LabelDictionary => labelDic;
+
+		/// <summary>
+		/// 変数全部。スクリプト中で必要になる変数は(ユーザーが直接触れないものも含め)この中にいれる
+		/// </summary>
+		private VariableEvaluator vEvaluator;
+		public VariableEvaluator VEvaluator => vEvaluator;
+		private ExpressionMediator exm;
+		private GameBase gamebase;
+		readonly IConsole console;
+		private IdentifierDictionary idDic;
+		ProcessState state;
+		ProcessState originalState;//リセットする時のために
+        bool noError;
+        //色々あって復活させてみる
+        bool initialiing;
+        public bool inInitializeing => initialiing;
+
+		public bool Initialize()
+		{
+			LexicalAnalyzer.UseMacro = false;
+            state = new ProcessState(console);
+            originalState = state;
+            initialiing = true;
+			#if !DEBUG
+            try
+            {
+	#endif
+				ParserMediator.Initialize(console);
+				if (ParserMediator.HasWarning)
+				{
+					ParserMediator.FlushWarningList();
+					if(MessageBox.Show("There is a problem with the config file.\nWould you like to close Emuera?","Config Error", MessageBoxButtons.YesNo)
+						== DialogResult.Yes)
+					{
+						console.PrintSystemLine("Processing was terminated because there was a problem with the config file and exit was selected");
+						return false;
+					}
+				}
+				AppContents.LoadContents();
+				
+                if (Config.UseKeyMacro && !Program.AnalysisMode)
+                {
+                    if (File.Exists(Program.ExeDir + "macro.txt"))
+                    {
+                        if (Config.DisplayReport)
+							console.PrintSystemLine("Loading macro.txt...");
+                        KeyMacro.LoadMacroFile(Program.ExeDir + "macro.txt");
+                    }
+                }
+                if (Config.UseReplaceFile && !Program.AnalysisMode)
+                {
+					if (File.Exists(Program.CsvDir + "_Replace.csv"))
+					{
+						if (Config.DisplayReport)
+							console.PrintSystemLine("Loading _Replace.csv...");
+						ConfigData.Instance.LoadReplaceFile(Program.CsvDir + "_Replace.csv");
+						if (ParserMediator.HasWarning)
+						{
+							ParserMediator.FlushWarningList();
+							if (MessageBox.Show("Abnormality is found in _Replace.csv.\nWould you like to close Emuera?", "_Replace.csv Error", MessageBoxButtons.YesNo)
+								== DialogResult.Yes)
+							{
+								console.PrintSystemLine("Processing was terminated because _Replace.csv file had an error and exit was selected");
+								return false;
+							}
+						}
+					}
+                }
+                Config.SetReplace(ConfigData.Instance);
+                //ここでBARを設定すれば、いいことに気づいた予感
+                console.setStBar(Config.DrawLineString);
+
+				if (Config.UseRenameFile)
+                {
+					if (File.Exists(Program.CsvDir + "_Rename.csv"))
+                    {
+                        if (Config.DisplayReport || Program.AnalysisMode)
+							console.PrintSystemLine("Loading _Rename.csv...");
+						ParserMediator.LoadEraExRenameFile(Program.CsvDir + "_Rename.csv");
+                    }
+                    else
+                        console.PrintError("csv\\_Rename.csv is missing");
+                }
+                if (!Config.DisplayReport)
+                {
+                    console.PrintSingleLine(Config.LoadLabel);
+                    console.RefreshStrings(true);
+                }
+				gamebase = new GameBase();
+                if (!gamebase.LoadGameBaseCsv(Program.CsvDir + "GAMEBASE.CSV"))
+                {
+                    console.PrintSystemLine("Processing was terminated because a problem occurred while loading GAMEBASE.CSV");
+                    return false;
+                }
+				console.SetWindowTitle(gamebase.ScriptWindowTitle);
+				GlobalStatic.GameBaseData = gamebase;
+
+				ConstantData constant = new ConstantData(gamebase);
+				constant.LoadData(Program.CsvDir, console, Config.DisplayReport);
+				GlobalStatic.ConstantData = constant;
+				_trainName = constant.GetCsvNameList(VariableCode.TRAINNAME);
+
+                vEvaluator = new VariableEvaluator(gamebase, constant);
+				GlobalStatic.VEvaluator = vEvaluator;
+
+				idDic = new IdentifierDictionary(vEvaluator.VariableData);
+				GlobalStatic.IdentifierDictionary = idDic;
+
+				StrForm.Initialize();
+				VariableParser.Initialize();
+
+				exm = new ExpressionMediator(this, vEvaluator, console);
+				GlobalStatic.EMediator = exm;
+
+				labelDic = new LabelDictionary();
+				GlobalStatic.LabelDictionary = labelDic;
+				HeaderFileLoader hLoader = new HeaderFileLoader(console, idDic, this);
+
+				LexicalAnalyzer.UseMacro = false;
+				if (!hLoader.LoadHeaderFiles(Program.ErbDir, Config.DisplayReport))
+				{
+					console.PrintSystemLine("Processing was terminated because a problem occurred while loading ERH files");
+					return false;
+				}
+				LexicalAnalyzer.UseMacro = idDic.UseMacro();
+
+				ErbLoader loader = new ErbLoader(console, exm, this);
+                if (Program.AnalysisMode)
+                    noError = loader.LoadErbs(Program.AnalysisFiles, labelDic);
+                else
+                    noError = loader.LoadErbFiles(Program.ErbDir, Config.DisplayReport, labelDic);
+                InitSystemProcess();
+                initialiing = false;
+				#if !DEBUG
+            }
+			catch (Exception e)
+			{
+				handleException(e, null, true);
+				console.PrintSystemLine("Processing was terminated because a fatal error has occurred during initialization");
+				return false;
+			}
+	#endif
+			if (labelDic == null)
+			{
+				return false;
+			}
+			state.Begin(BeginType.TITLE);
+			GC.Collect();
+            return true;
+		}
+
+		public void ReloadErb()
+		{
+			saveCurrentState(false);
+			state.SystemState = SystemStateCode.System_Reloaderb;
+			ErbLoader loader = new ErbLoader(console, exm, this);
+            loader.LoadErbFiles(Program.ErbDir, false, labelDic);
+			console.ReadAnyKey();
+		}
+
+		public void ReloadPartialErb(List<string> path)
+		{
+			saveCurrentState(false);
+			state.SystemState = SystemStateCode.System_Reloaderb;
+			ErbLoader loader = new ErbLoader(console, exm, this);
+			loader.LoadErbs(path, labelDic);
+			console.ReadAnyKey();
+		}
+
+		public void SetCommnds(Int64 count)
+		{
+			coms = new List<long>((int)count);
+			isCTrain = true;
+			Int64[] selectcom = vEvaluator.SELECTCOM_ARRAY;
+			if (count >= selectcom.Length)
+			{
+				throw new CodeEE("The value of the arguments of the CALLTRAIN instruction exceeds the number of SELECTCOM elements");
+			}
+			for (int i = 0; i < (int)count; i++)
+			{
+				coms.Add(selectcom[i + 1]);
+			}
+		}
+
+        public bool ClearCommands()
+        {
+            coms.Clear();
+            count = 0;
+            isCTrain = false;
+            skipPrint = true;
+            return (CallFunction("CALLTRAINEND", false, false));
+        }
+
+		public void InputInteger(Int64 i)
+		{
+			vEvaluator.RESULT = i;
+		}
+		public void InputSystemInteger(Int64 i)
+		{
+			_systemResult = i;
+		}
+		public void InputString(string s)
+		{
+			vEvaluator.RESULTS = s;
+		}
+
+		private uint startTime;
+		
+		public void DoScript()
+		{
+			startTime = WinmmTimer.TickCount;
+			state.lineCount = 0;
+			bool systemProcRunning = true;
+			try
+			{
+				while (true)
+				{
+					methodStack = 0;
+					systemProcRunning = true;
+					while (state.ScriptEnd && console.IsRunning)
+						RunSystemProc();
+					if (!console.IsRunning)
+						break;
+					systemProcRunning = false;
+					runScriptProc(true);
+				}
+			}
+			catch (Exception ec)
+			{
+				LogicalLine currentLine = state.ErrorLine;
+				if (currentLine != null && currentLine is NullLine)
+					currentLine = null;
+				if (systemProcRunning)
+					handleExceptionInSystemProc(ec, currentLine, true);
+				else
+					handleException(ec, currentLine, true);
+			}
+		}
+		
+		public void BeginTitle()
+		{
+			vEvaluator.ResetData();
+			state = originalState;
+			state.Begin(BeginType.TITLE);
+		}
+
+		private void checkInfiniteLoop()
+		{
+			//うまく動かない。BEEP音が鳴るのを止められないのでこの処理なかったことに(1.51)
+			////フリーズ防止。処理中でも履歴を見たりできる
+			//System.Windows.Forms.Application.DoEvents();
+			////System.Threading.Thread.Sleep(0);
+
+			//if (!console.Enabled)
+			//{
+			//    //DoEvents()の間にウインドウが閉じられたらおしまい。
+			//    console.ReadAnyKey();
+			//    return;
+			//}
+
+
+
+
+			//uint time = WinmmTimer.TickCount - startTime;
+			//if (time < Config.InfiniteLoopAlertTime)
+			//	return;
+			//LogicalLine currentLine = state.CurrentLine;
+			//if ((currentLine == null) || (currentLine is NullLine))
+			//	return;//現在の行が特殊な状態ならスルー
+			//if (!console.Enabled)
+			//	return;//クローズしてるとMessageBox.Showができないので。
+			//string caption = "There is a possibility of an infinite loop";
+			//string text = string.Format(
+			//	"Currently {1} line at {0} is being executed.\nSince the last input {3} milliseconds has passed and the line was executed {2} times.\nWould you like to forcibly terminate processing?",
+			//	currentLine.Position.Filename, currentLine.Position.LineNo, state.lineCount, time);
+			//DialogResult result = MessageBox.Show(text, caption, MessageBoxButtons.YesNo);
+			//if (result == DialogResult.Yes)
+			//{
+			//	throw new CodeEE("Forced termination was selected due to suspected infinite loop");
+			//}
+
+			//state.lineCount = 0;
+			//startTime = WinmmTimer.TickCount;
+		}
+
+		int methodStack;
+		public SingleTerm GetValue(SuperUserDefinedMethodTerm udmt,bool translate = false)
+		{
+			methodStack++;
+            if (methodStack > 100)
+            {
+                //StackOverflowExceptionはcatchできない上に再現性がないので発生前に一定数で打ち切る。
+                //環境によっては100以前にStackOverflowExceptionがでるかも?
+                throw new CodeEE("Call stack of the function has overflowed (is it being recursively called indefinitely?)");
+            }
+            SingleTerm ret = null;
+            int temp_current = state.currentMin;
+            state.currentMin = state.functionCount;
+            udmt.Call.updateRetAddress(state.CurrentLine);
+            try
+            {
+				state.IntoFunction(udmt.Call, udmt.Argument, exm);
+                //do whileの中でthrow されたエラーはここではキャッチされない。
+				//#functionを全て抜けてDoScriptでキャッチされる。
+    			runScriptProc(translate);
+                ret = state.MethodReturnValue;
+			}
+			finally
+			{
+				if (udmt.Call.TopLabel.hasPrivDynamicVar)
+					udmt.Call.TopLabel.Out();
+                //1756beta2+v3:こいつらはここにないとデバッグコンソールで式中関数が事故った時に大事故になる
+                state.currentMin = temp_current;
+                methodStack--;
+            }
+			return ret;
+		}
+
+        public void clearMethodStack()
+        {
+            methodStack = 0;
+        }
+
+        public int MethodStack()
+        {
+            return methodStack;
+        }
+
+		public ScriptPosition GetRunningPosition()
+		{
+			LogicalLine line = state.ErrorLine;
+			if (line == null)
+				return null;
+			return line.Position;
+		}
+
+		private readonly string scaningScope = null;
+		private string GetScaningScope()
+		{
+			if (scaningScope != null)
+				return scaningScope;
+			return state.Scope;
+		}
+
+		public LogicalLine scaningLine = null;
+		internal LogicalLine GetScaningLine()
+		{
+			if (scaningLine != null)
+				return scaningLine;
+			LogicalLine line = state.ErrorLine;
+			if (line == null)
+				return null;
+			return line;
+		}
+		
+		
+		private void handleExceptionInSystemProc(Exception exc, LogicalLine current, bool playSound)
+		{
+			console.ThrowError(playSound);
+			if (exc is CodeEE)
+			{
+				console.PrintError("An error has occurred at the end of the function: " + Program.ExeName);
+				console.PrintError(exc.Message);
+			}
+			else if (exc is ExeEE)
+			{
+				console.PrintError("An Emuera error has occurred at the end of the function: " + Program.ExeName);
+				console.PrintError(exc.Message);
+			}
+			else
+			{
+				console.PrintError("An unexpected error has occurred at the end of the function: " + Program.ExeName);
+				console.PrintError(exc.GetType() + ":" + exc.Message);
+				string[] stack = exc.StackTrace.Split('\n');
+				for (int i = 0; i < stack.Length; i++)
+				{
+					console.PrintError(stack[i]);
+				}
+			}
+		}
+		
+		private void handleException(Exception exc, LogicalLine current, bool playSound)
+		{
+			console.ThrowError(playSound);
+			ScriptPosition position = null;
+			EmueraException ee = exc as EmueraException;
+			if((ee != null) && (ee.Position != null))
+				position = ee.Position;
+            else if ((current != null) && (current.Position != null))
+				position = current.Position;
+			string posString = "";
+			if (position != null)
+			{
+				if (position.LineNo >= 0)
+					posString = position.Filename + " at line " + position.LineNo + " ";
+				else
+					posString = position.Filename + "で";
+					
+			}
+			if (exc is CodeEE)
+			{
+                if (position != null)
+				{
+                    InstructionLine procline = current as InstructionLine;
+                    if (procline != null && procline.FunctionCode == FunctionCode.THROW)
+                    {
+                        console.PrintErrorButton(posString + "THROW has occurred", position);
+                        if (position.RowLine != null)
+                            console.PrintError(position.RowLine);
+                        console.PrintError("THROW contents: " + exc.Message);
+                    }
+                    else
+                    {
+						console.PrintErrorButton(posString + "Error has occurred:" + Program.ExeName, position);
+                        if (position.RowLine != null)
+                            console.PrintError(position.RowLine);
+                        console.PrintError("Error description: " + exc.Message);
+                    }
+                    console.PrintError("Function: @" + current.ParentLabelLine.LabelName + "(file:" + current.ParentLabelLine.Position.Filename + " in line " + current.ParentLabelLine.Position.LineNo + ")");
+                    console.PrintError("Function call stack: ");
+                    LogicalLine parent = null;
+                    int depth = 0;
+                    while ((parent = state.GetReturnAddressSequensial(depth++)) != null)
+                    {
+                        if (parent.Position != null)
+                        {
+                            console.PrintErrorButton("↑" + parent.Position.Filename + " at line " + parent.Position.LineNo + "(function@" + parent.ParentLabelLine.LabelName + ")", parent.Position);
+                        }
+                    } 
+				}
+				else
+				{
+					console.PrintError(posString + "Error has occurred: " + Program.ExeName);
+					console.PrintError(exc.Message);
+				}
+			}
+			else if (exc is ExeEE)
+			{
+				console.PrintError(posString + "Emuera has encountered an error: " + Program.ExeName);
+				console.PrintError(exc.Message);
+			}
+			else
+            {
+				console.PrintError(posString + "Unexpected error has occurred: " + Program.ExeName);
+				console.PrintError(exc.GetType() + ":" + exc.Message);
+				string[] stack = exc.StackTrace.Split('\n');
+				for (int i = 0; i < stack.Length; i++)
+				{
+					console.PrintError(stack[i]);
+				}
+			}
+		}
+
+
+	}
+}

+ 190 - 0
NTERA/Game/GameProc/UserDefinedFunction.cs

@@ -0,0 +1,190 @@
+using System.Collections.Generic;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameProc
+{
+	internal enum UserDifinedFunctionDataArgType
+	{
+		Null,
+		Int = 0x10,
+		Str = 0x20,
+
+		RefInt1 = 0x51,
+		RefInt2 = 0x52,
+		RefInt3 = 0x53,
+		RefStr1 = 0x61,
+		RefStr2 = 0x62,
+		RefStr3 = 0x63,
+		__Ref = 0x40,
+		__Dimention = 0x0F
+	}
+
+	internal sealed class UserDefinedFunctionData
+	{
+		private UserDefinedFunctionData()
+		{
+		}
+		public string Name;
+		public bool TypeIsStr;
+		public UserDifinedFunctionDataArgType[] ArgList;
+
+		public static UserDefinedFunctionData Create(WordCollection wc, bool dims, ScriptPosition sc)
+		{
+			string dimtype = dims ? "#FUNCTION" : "#FUNCTIONS";
+			UserDefinedFunctionData ret = new UserDefinedFunctionData();
+			ret.TypeIsStr = dims;
+			IdentifierWord idw = null;
+			string keyword = dimtype;
+			while (!wc.EOL && (idw = wc.Current as IdentifierWord) != null)
+			{
+				wc.ShiftNext();
+				keyword = idw.Code;
+				if (Config.ICVariable)
+					keyword = keyword.ToUpper();
+				switch (keyword)
+				{
+					case "CONST":
+					case "REF":
+					case "DYNAMIC":
+					case "STATIC":
+					case "GLOBAL":
+					case "SAVEDATA":
+					case "CHARADATA":
+						throw new CodeEE(dims + "中では" + keyword + "キーワードは指定できません", sc);
+					default:
+						ret.Name = keyword;
+						goto whilebreak;
+				}
+			}
+		whilebreak:
+			if (ret.Name == null)
+				throw new CodeEE(keyword + "の後に有効な識別子が指定されていません", sc);
+			if (wc.EOL || wc.Current.Type != '(')
+				throw new CodeEE("識別子の後に引数定義がありません", sc);
+			string errMes = "";
+			int errLevel = -1;
+			GlobalStatic.IdentifierDictionary.CheckUserLabelName(ref errMes, ref errLevel, true, ret.Name);
+			if (errLevel == 0)//関数と変数の両方からチェック エラーメッセージが微妙だがひとまず気にしない
+				GlobalStatic.IdentifierDictionary.CheckUserVarName(ref errMes, ref errLevel, ret.Name);
+			if (errLevel >= 0)
+			{
+				if (errLevel >= 2)
+					throw new CodeEE(errMes, sc);
+				ParserMediator.Warn(errMes, sc, errLevel);
+			}
+			List<UserDifinedFunctionDataArgType> argList = new List<UserDifinedFunctionDataArgType>();
+			UserDifinedFunctionDataArgType argType = UserDifinedFunctionDataArgType.Null;
+
+			int state = 0;
+			//0=初期状態 1=カンマ括弧閉じ待ち 2=カンマ直後
+			//3=REF後INTorSTR待ち 4=':'or','待ち 5=':'or '0'or ','待ち
+			while (true)// REF INT STR 0 '*' ',' ')' のみで構成されるはず
+			{
+				wc.ShiftNext();
+				switch (wc.Current.Type)
+				{
+					case '\0':
+						throw new CodeEE("括弧が閉じられていません", sc);
+					case ')':
+						if (state == 0 || state == 1)
+							goto argend;
+						if (state == 4 || state == 5)
+						{
+							if ((int)(argType & UserDifinedFunctionDataArgType.__Dimention) == 0)
+								throw new CodeEE("REF引数は配列変数でなければなりません", sc);
+							state = 2;
+							argList.Add(argType);
+							goto argend;
+						}
+						throw new CodeEE("予期しない括弧です", sc);
+					case '0':
+						if (((LiteralIntegerWord)wc.Current).Int != 0)
+							goto argerr;
+						if (state == 5)
+						{
+							state = 4;
+							continue;
+						}
+						goto argerr;
+					case ':':
+						if (state == 4 || state == 5)
+						{
+							state = 5;
+							argType++; if ((int)(argType & UserDifinedFunctionDataArgType.__Dimention) > 3)
+								throw new CodeEE("REF引数は4次元以上の配列にできません", sc);
+							continue;
+						}
+						goto argerr;
+					case ',':
+						if (state == 1)
+						{
+							state = 2;
+							continue;
+						}
+						if (state == 4 || state == 5)
+						{
+							if ((int)(argType & UserDifinedFunctionDataArgType.__Dimention) == 0)
+								throw new CodeEE("REF引数は配列変数でなければなりません", sc);
+							state = 2;
+							argList.Add(argType);
+							continue;
+						}
+						goto argerr;
+					case 'A':
+						{
+							string str = ((IdentifierWord)wc.Current).Code;
+							if (Config.ICVariable)
+								str = str.ToUpper();
+							if (str == "REF")
+							{
+								if (state == 0 || state == 2)
+								{
+									state = 3;
+									continue;
+								}
+								goto argerr;
+							}
+
+							if (str == "INT" || str == "STR")
+							{
+								if (str == "INT")
+									argType = UserDifinedFunctionDataArgType.Int;
+								else
+									argType = UserDifinedFunctionDataArgType.Str;
+								if (state == 0 || state == 2)
+								{
+									state = 1;
+									argList.Add(argType);
+									continue;
+								}
+								if (state == 3)
+								{
+									argType = argType | UserDifinedFunctionDataArgType.__Ref;
+									state = 4;
+									continue;
+								}
+								goto argerr;
+							}
+
+							goto argerr;
+						}
+					default:
+						goto argerr;
+				}
+			}
+		argend:
+			wc.ShiftNext();
+			if (!wc.EOL)
+				throw new CodeEE("宣言の後に余分な文字があります", sc);
+			ret.ArgList = new UserDifinedFunctionDataArgType[argList.Count];
+			argList.CopyTo(ret.ArgList);
+			return ret;
+		argerr:
+			if (!wc.EOL)
+				throw new CodeEE("引数の解析中に予期しないトークン" + wc.Current + "を発見しました", sc);
+			throw new CodeEE("引数の解析中にエラーが発生しました", sc);
+		}
+
+	}
+
+}

+ 313 - 0
NTERA/Game/GameProc/UserDefinedVariable.cs

@@ -0,0 +1,313 @@
+using System;
+using System.Collections.Generic;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.Sub;
+
+namespace MinorShift.Emuera.GameProc
+{
+
+	internal sealed class UserDefinedVariableData
+	{
+		public string Name;
+		public bool TypeIsStr;
+		public bool Reference;
+		public int Dimension = 1;
+		public int[] Lengths;
+		public Int64[] DefaultInt;
+		public string[] DefaultStr;
+		public bool Global;
+		public bool Save;
+		public bool Static = true;
+		public bool Private;
+		public bool CharaData;
+		public bool Const;
+		public static UserDefinedVariableData Create(WordCollection wc, bool dims, bool isPrivate, ScriptPosition sc)
+		{
+			string dimtype = dims ? "#DIM" : "#DIMS";
+			UserDefinedVariableData ret = new UserDefinedVariableData();
+			ret.TypeIsStr = dims;
+
+			IdentifierWord idw = null;
+			bool staticDefined = false;
+			ret.Const = false;
+			string keyword = dimtype;
+			List<string> keywords = new List<string>();
+			while (!wc.EOL && (idw = wc.Current as IdentifierWord) != null)
+			{
+				wc.ShiftNext();
+				keyword = idw.Code;
+				if (Config.ICVariable)
+					keyword = keyword.ToUpper();
+				//TODO ifの数があたまわるい なんとかしたい
+				switch (keyword)
+				{
+					case "CONST":
+						if (ret.CharaData)
+							throw new CodeEE(keyword + "とCHARADATAキーワードは同時に指定できません", sc);
+						if (ret.Global)
+							throw new CodeEE(keyword + "とGLOBALキーワードは同時に指定できません", sc);
+						if (ret.Save)
+							throw new CodeEE(keyword + "とSAVEDATAキーワードは同時に指定できません", sc);
+						if (ret.Reference)
+							throw new CodeEE(keyword + "とREFキーワードは同時に指定できません", sc);
+						if (!ret.Static)
+							throw new CodeEE(keyword + "とDYNAMICキーワードは同時に指定できません", sc);
+						if (ret.Const)
+							throw new CodeEE(keyword + "キーワードが二重に指定されています", sc);
+						ret.Const = true;
+						break;
+					case "REF":
+						//throw new CodeEE("未実装の機能です", sc);
+						//if (!isPrivate)
+						//	throw new CodeEE("広域変数の宣言に" + keyword + "キーワードは指定できません", sc);
+						if (staticDefined && ret.Static)
+							throw new CodeEE(keyword + "とSTATICキーワードは同時に指定できません", sc);
+						if (ret.CharaData)
+							throw new CodeEE(keyword + "とCHARADATAキーワードは同時に指定できません", sc);
+						if (ret.Global)
+							throw new CodeEE(keyword + "とGLOBALキーワードは同時に指定できません", sc);
+						if (ret.Save)
+							throw new CodeEE(keyword + "とSAVEDATAキーワードは同時に指定できません", sc);
+						if (ret.Const)
+							throw new CodeEE(keyword + "とCONSTキーワードは同時に指定できません", sc);
+						if (ret.Reference)
+							throw new CodeEE(keyword + "キーワードが二重に指定されています", sc);
+						ret.Reference = true;
+						ret.Static = true;
+						break;
+					case "DYNAMIC":
+						if (!isPrivate)
+							throw new CodeEE("広域変数の宣言に" + keyword + "キーワードは指定できません", sc);
+						if (ret.CharaData)
+							throw new CodeEE(keyword + "とCHARADATAキーワードは同時に指定できません", sc);
+						if (ret.Const)
+							throw new CodeEE(keyword + "とCONSTキーワードは同時に指定できません", sc);
+						if (staticDefined)
+							if (ret.Static)
+								throw new CodeEE("STATICとDYNAMICキーワードは同時に指定できません", sc);
+							else
+								throw new CodeEE(keyword + "キーワードが二重に指定されています", sc);
+						staticDefined = true;
+						ret.Static = false;
+						break;
+					case "STATIC":
+						if (!isPrivate)
+							throw new CodeEE("広域変数の宣言に" + keyword + "キーワードは指定できません", sc);
+						if (ret.CharaData)
+							throw new CodeEE(keyword + "とCHARADATAキーワードは同時に指定できません", sc);
+						if (staticDefined)
+							if (!ret.Static)
+								throw new CodeEE("STATICとDYNAMICキーワードは同時に指定できません", sc);
+							else
+								throw new CodeEE(keyword + "キーワードが二重に指定されています", sc);
+						if (ret.Reference)
+							throw new CodeEE(keyword + "とREFキーワードは同時に指定できません", sc);
+						staticDefined = true;
+						ret.Static = true;
+						break;
+					case "GLOBAL":
+						if (isPrivate)
+							throw new CodeEE("ローカル変数の宣言に" + keyword + "キーワードは指定できません", sc);
+						if (ret.CharaData)
+							throw new CodeEE(keyword + "とCHARADATAキーワードは同時に指定できません", sc);
+						if (ret.Reference)
+							throw new CodeEE(keyword + "とREFキーワードは同時に指定できません", sc);
+						if (ret.Const)
+							throw new CodeEE(keyword + "とCONSTキーワードは同時に指定できません", sc);
+						if (staticDefined)
+							if (ret.Static)
+								throw new CodeEE("STATICとGLOBALキーワードは同時に指定できません", sc);
+							else
+								throw new CodeEE("DYNAMICとGLOBALキーワードは同時に指定できません", sc);
+						ret.Global = true;
+						break;
+					case "SAVEDATA":
+						if (isPrivate)
+							throw new CodeEE("ローカル変数の宣言に" + keyword + "キーワードは指定できません", sc);
+						if (staticDefined)
+							if (ret.Static)
+								throw new CodeEE("STATICとSAVEDATAキーワードは同時に指定できません", sc);
+							else
+								throw new CodeEE("DYNAMICとSAVEDATAキーワードは同時に指定できません", sc);
+						if (ret.Reference)
+							throw new CodeEE(keyword + "とREFキーワードは同時に指定できません", sc);
+						if (ret.Const)
+							throw new CodeEE(keyword + "とCONSTキーワードは同時に指定できません", sc);
+						if (ret.Save)
+							throw new CodeEE(keyword + "キーワードが二重に指定されています", sc);
+						ret.Save = true;
+						break;
+					case "CHARADATA":
+						if (isPrivate)
+							throw new CodeEE("ローカル変数の宣言に" + keyword + "キーワードは指定できません", sc);
+						if (ret.Reference)
+							throw new CodeEE(keyword + "とREFキーワードは同時に指定できません", sc);
+						if (ret.Const)
+							throw new CodeEE(keyword + "とCONSTキーワードは同時に指定できません", sc);
+						if (staticDefined)
+							if (ret.Static)
+                                throw new CodeEE(keyword + "とSTATICキーワードは同時に指定できません", sc);
+							else
+                                throw new CodeEE(keyword + "とDYNAMICキーワードは同時に指定できません", sc);
+						if (ret.Global)
+                            throw new CodeEE(keyword + "とGLOBALキーワードは同時に指定できません", sc);
+						if (ret.CharaData)
+							throw new CodeEE(keyword + "キーワードが二重に指定されています", sc);
+						ret.CharaData = true;
+						break;
+					default:
+						ret.Name = keyword;
+						goto whilebreak;
+				}
+			}
+		whilebreak:
+			if (ret.Name == null)
+				throw new CodeEE(keyword + "の後に有効な変数名が指定されていません", sc);
+			string errMes = "";
+			int errLevel = -1;
+			if (isPrivate)
+				GlobalStatic.IdentifierDictionary.CheckUserPrivateVarName(ref errMes, ref errLevel, ret.Name);
+			else
+				GlobalStatic.IdentifierDictionary.CheckUserVarName(ref errMes, ref errLevel, ret.Name);
+			if (errLevel >= 0)
+			{
+				if (errLevel >= 2)
+					throw new CodeEE(errMes, sc);
+				ParserMediator.Warn(errMes, sc, errLevel);
+			}
+
+
+			List<int> sizeNum = new List<int>();
+			if (wc.EOL)//サイズ省略
+			{
+				if (ret.Const)
+					throw new CodeEE("CONSTキーワードが指定されていますが初期値が設定されていません");
+				sizeNum.Add(1);
+			}
+			else if (wc.Current.Type == ',')//サイズ指定
+			{
+				while (!wc.EOL)
+				{
+					if (wc.Current.Type == '=')//サイズ指定解読完了&初期値指定
+						break;
+					if (wc.Current.Type != ',')
+						throw new CodeEE("書式が間違っています", sc);
+					wc.ShiftNext();
+					if (ret.Reference)//参照型の場合は要素数不要
+					{
+						sizeNum.Add(0);
+						if (wc.EOL)
+							break;
+						if (wc.Current.Type == ',')
+							continue;
+					}
+					if (wc.EOL)
+						throw new CodeEE("カンマの後に有効な定数式が指定されていません", sc);
+					IOperandTerm arg = ExpressionParser.ReduceIntegerTerm(wc, TermEndWith.Comma_Assignment);
+					SingleTerm sizeTerm = arg.Restructure(null) as SingleTerm;
+					if ((sizeTerm == null) || (sizeTerm.GetOperandType() != typeof(Int64)))
+						throw new CodeEE("カンマの後に有効な定数式が指定されていません", sc);
+					if (ret.Reference)//参照型には要素数指定不可(0にするか書かないかどっちか
+					{
+						if (sizeTerm.Int != 0)
+							throw new CodeEE("参照型変数にはサイズを指定できません(サイズを省略するか0を指定してください)", sc);
+
+						continue;
+					}
+
+					if ((sizeTerm.Int <= 0) || (sizeTerm.Int > 1000000))
+						throw new CodeEE("ユーザー定義変数のサイズは1以上1000000以下でなければなりません", sc);
+					sizeNum.Add((int)sizeTerm.Int);
+				}
+			}
+
+
+			if (wc.Current.Type != '=')//初期値指定なし
+			{
+				if (ret.Const)
+					throw new CodeEE("CONSTキーワードが指定されていますが初期値が設定されていません");
+			}
+			else//初期値指定あり
+			{
+				if (((OperatorWord)wc.Current).Code != OperatorCode.Assignment)
+					throw new CodeEE("予期しない演算子を発見しました");
+				if (ret.Reference)
+					throw new CodeEE("参照型変数には初期値を設定できません");
+				if (sizeNum.Count >= 2)
+					throw new CodeEE("多次元変数には初期値を設定できません");
+				if (ret.CharaData)
+					throw new CodeEE("キャラ型変数には初期値を設定できません");
+				int size = 0;
+				if (sizeNum.Count == 1)
+					size = sizeNum[0];
+				wc.ShiftNext();
+				IOperandTerm[] terms = ExpressionParser.ReduceArguments(wc, ArgsEndWith.EoL, false);
+				if (terms.Length == 0)
+					throw new CodeEE("配列の初期値は省略できません");
+				if (size > 0)
+				{
+					if (terms.Length > size)
+						throw new CodeEE("初期値の数が配列のサイズを超えています");
+					if (ret.Const && terms.Length != size)
+						throw new CodeEE("定数の初期値の数が配列のサイズと一致しません");
+				}
+				if (dims)
+					ret.DefaultStr = new string[terms.Length];
+				else
+					ret.DefaultInt = new Int64[terms.Length];
+
+				for (int i = 0; i < terms.Length; i++)
+				{
+					if (terms[i] == null)
+						throw new CodeEE("配列の初期値は省略できません");
+					terms[i] = terms[i].Restructure(GlobalStatic.EMediator);
+					SingleTerm sTerm = terms[i] as SingleTerm;
+					if (sTerm == null)
+						throw new CodeEE("配列の初期値には定数のみ指定できます");
+					if (dims != sTerm.IsString)
+						throw new CodeEE("変数の型と初期値の型が一致していません");
+					if (dims)
+						ret.DefaultStr[i] = sTerm.Str;
+					else
+						ret.DefaultInt[i] = sTerm.Int;
+				}
+				if (sizeNum.Count == 0)
+					sizeNum.Add(terms.Length);
+			}
+			if (!wc.EOL)
+				throw new CodeEE("書式が間違っています", sc);
+
+			if (sizeNum.Count == 0)
+				sizeNum.Add(1);
+
+			ret.Private = isPrivate;
+			ret.Dimension = sizeNum.Count;
+			if (ret.Const && ret.Dimension > 1)
+				throw new CodeEE("CONSTキーワードが指定された変数を多次元配列にはできません");
+			if (ret.CharaData && ret.Dimension > 2)
+				throw new CodeEE("3次元以上のキャラ型変数を宣言することはできません", sc);
+			if (ret.Dimension > 3)
+				throw new CodeEE("4次元以上の配列変数を宣言することはできません", sc);
+			ret.Lengths = new int[sizeNum.Count];
+			if (ret.Reference)
+				return ret;
+			Int64 totalBytes = 1;
+			for (int i = 0; i < sizeNum.Count; i++)
+			{
+				ret.Lengths[i] = sizeNum[i];
+				totalBytes *= ret.Lengths[i];
+			}
+			if ((totalBytes <= 0) || (totalBytes > 1000000))
+				throw new CodeEE("ユーザー定義変数のサイズは1以上1000000以下でなければなりません", sc);
+			if (!isPrivate && ret.Save && !Config.SystemSaveInBinary)
+			{
+				if (dims && ret.Dimension > 1)
+					throw new CodeEE("文字列型の多次元配列変数にSAVEDATAフラグを付ける場合には「バイナリ型セーブ」オプションが必須です", sc);
+				if (ret.CharaData)
+					throw new CodeEE("キャラ型変数にSAVEDATAフラグを付ける場合には「バイナリ型セーブ」オプションが必須です", sc);
+			}
+			return ret;
+		}
+	}
+
+}

+ 56 - 0
NTERA/Game/GlobalStatic.cs

@@ -0,0 +1,56 @@
+using System.Collections.Generic;
+using MinorShift.Emuera.GameData;
+using MinorShift.Emuera.GameData.Expression;
+using MinorShift.Emuera.GameData.Variable;
+using MinorShift.Emuera.GameProc;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera
+{
+	/* 1756 作成
+	 * できるだけデータはprivateにして必要なものだけが参照するようにしようという設計だったのは今は昔。
+	 * 改変のたびにProcess.Instance.XXXなんかがどんどん増えていく。
+	 * まあ、増えるのは仕方ないと諦める事にして、行儀の悪い参照の仕方をするものたちをせめて一箇所に集めて管理しようという計画である。
+	 * これからはInstanceを public static に解放することはやめ、ここから参照する。
+	 * しかし、できるならここからの参照は減らしたい。
+	 */
+	internal static class GlobalStatic
+	{
+		//これは生成される順序で並んでいる。
+		//下から上を参照した場合、nullを返されることがある。
+		//Config Replace
+		public static IConsole Console;
+		public static IMainWindow MainWindow;
+		public static Process Process;
+		//Config.RenameDic
+		public static GameBase GameBaseData;
+		public static ConstantData ConstantData;
+		public static VariableData VariableData;
+		//StrForm
+		public static VariableEvaluator VEvaluator;
+		public static IdentifierDictionary IdentifierDictionary;
+		public static ExpressionMediator EMediator;
+		//
+		public static LabelDictionary LabelDictionary;
+
+
+		//ERBloaderに引数解析の結果を渡すための橋渡し変数
+		//1756 Processから移動。Program.AnalysisMode用
+		public static readonly Dictionary<string, long> tempDic = new Dictionary<string, long>();
+#if DEBUG
+		public static List<FunctionLabelLine> StackList = new List<FunctionLabelLine>();
+#endif
+		public static void Reset()
+		{
+			Process = null;
+			ConstantData = null;
+			GameBaseData = null;
+			EMediator = null;
+			VEvaluator = null;
+			VariableData = null;
+			LabelDictionary = null;
+			IdentifierDictionary = null;
+			tempDic.Clear();
+		}
+	}
+}

+ 133 - 0
NTERA/Game/Sub/EmueraException.cs

@@ -0,0 +1,133 @@
+using System;
+using System.Collections.Generic;
+
+namespace MinorShift.Emuera.Sub
+{
+	[Serializable]
+    internal abstract class EmueraException : ApplicationException
+	{
+		protected EmueraException(string errormes, ScriptPosition position)
+			: base(errormes)
+		{
+			Position = position;
+		}
+		protected EmueraException(string errormes)
+			: base(errormes)
+		{
+			Position = null;
+		}
+		public ScriptPosition Position;
+	}
+
+	/// <summary>
+	/// emuera本体に起因すると思われるエラー
+	/// </summary>
+    [Serializable]
+    internal sealed class ExeEE : EmueraException
+	{
+		public ExeEE(string errormes)
+			: base(errormes)
+		{
+		}
+		public ExeEE(string errormes, ScriptPosition position)
+			: base(errormes, position)
+		{
+		}
+	}
+
+	/// <summary>
+	/// スクリプト側に起因すると思われるエラー
+	/// </summary>
+    [Serializable]
+    internal class CodeEE : EmueraException
+	{
+		public CodeEE(string errormes, ScriptPosition position)
+			: base(errormes, position)
+		{
+		}
+		public CodeEE(string errormes)
+			: base(errormes)
+		{
+		}
+	}
+
+	/// <summary>
+	/// 未実装エラー
+	/// </summary>
+    [Serializable]
+    internal sealed class NotImplCodeEE : CodeEE
+	{
+		public NotImplCodeEE(ScriptPosition position)
+			: base("This function cannot be used in the current version", position)
+		{
+		}
+		public NotImplCodeEE()
+			: base("This function cannot be used in the current version")
+		{
+		}
+	}
+
+	/// <summary>
+	/// Save, Load中のエラー
+	/// </summary>
+    [Serializable]
+    internal sealed class FileEE : EmueraException
+	{
+		public FileEE(string errormes)
+			: base(errormes)
+		{ }
+	}
+
+	/// <summary>
+	/// エラー箇所を表示するための位置データ。整形前のデータなのでエラー表示以外の理由で参照するべきではない。
+	/// </summary>
+	public class ScriptPosition : IEquatable<ScriptPosition>, IEqualityComparer<ScriptPosition>
+	{
+		public ScriptPosition(string srcLine)
+		{
+			LineNo = -1;
+		    RowLine = srcLine != null ? string.Intern(srcLine) : srcLine;
+            Filename = "";
+		}
+		public ScriptPosition(string srcFile, int srcLineNo, string srcLine)
+		{
+			LineNo = srcLineNo;
+		    RowLine = srcLine != null ? string.Intern(srcLine) : srcLine;
+            Filename = srcFile ?? "";
+		}
+		public readonly int LineNo;
+		public readonly string RowLine;
+		public readonly string Filename;
+		public override string ToString()
+		{
+			if(LineNo == -1)
+				return base.ToString();
+			return Filename + ":" + LineNo;
+		}
+
+		#region IEqualityComparer<ScriptPosition> メンバ
+
+		public bool Equals(ScriptPosition x, ScriptPosition y)
+		{
+			if((x == null)||(y == null))
+				return false;
+			return ((x.Filename == y.Filename) && (x.LineNo == y.LineNo));
+		}
+
+		public int GetHashCode(ScriptPosition obj)
+		{
+			return Filename.GetHashCode() ^ LineNo.GetHashCode();
+		}
+
+		#endregion
+
+		#region IEquatable<ScriptPosition> メンバ
+
+		public bool Equals(ScriptPosition other)
+		{
+			return Equals(this, other);
+		}
+
+		#endregion
+	}
+}

+ 727 - 0
NTERA/Game/Sub/EraBinaryDataReader.cs

@@ -0,0 +1,727 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace MinorShift.Emuera.Sub
+{
+	#region reader/writer共通データ
+	public enum EraSaveFileType : byte
+	{
+		Normal = 0x00,
+		Global = 0x01,
+		Var = 0x02,
+		CharVar = 0x03
+	}
+
+	public enum EraSaveDataType : byte
+	{
+		Int = 0x00,
+		IntArray = 0x01,
+		IntArray2D = 0x02,
+		IntArray3D = 0x03,
+		Str = 0x10,
+		StrArray = 0x11,
+		StrArray2D = 0x12,
+		StrArray3D = 0x13,
+		//SOC = 0xFD,//キャラデータ始まり
+		Separator = 0xFD,//データ区切り
+		EOC = 0xFE,//キャラデータ終わり
+		EOF = 0xFF//ファイル終端
+	}
+
+	static class Ebdb//EraBinaryData中のマジックナンバーなバイト
+	{
+		public const byte Byte = 0xCF;
+		public const byte Int16 = 0xD0;//直後の2バイトがInt16
+		public const byte Int32 = 0xD1;//直後の4バイトがInt32
+		public const byte Int64 = 0xD2;//直後の8バイトがInt64
+		public const byte String = 0xD8;//直後がString
+
+		public const byte EoA1 = 0xE0;//データ区切り(一次元
+		public const byte EoA2 = 0xE1;//データ区切り(二次元
+		public const byte Zero = 0xF0;//直後にゼロが連続する数
+		public const byte ZeroA1 = 0xF1;//直後に空配列が連続する数(一次元
+		public const byte ZeroA2 = 0xF2;//直後に空配列が連続する数(二次元
+		public const byte EoD = 0xFF;//変数データ終わり
+	}
+
+	static class EraBDConst
+	{
+		//Headerはpngのパクリ
+		public const UInt64 Header = 0x0A1A0A0D41524589UL;
+		public const UInt32 Version1808 = 1808;
+		public const UInt32 DataCount = 0;
+	}
+	#endregion
+
+	/// <summary>
+	/// 1808追加 新しいデータ保存形式
+	/// 将来形式を変更したときのためにabstractにしておく
+	/// </summary>
+	internal abstract class EraBinaryDataReader : IDisposable
+	{
+		private EraBinaryDataReader() {}
+		
+		protected EraBinaryDataReader(BinaryReader stream, int ver, UInt32[] buf)
+		{
+			reader = stream;
+			version = ver;
+			data = buf;
+		}
+		protected BinaryReader reader;
+		protected readonly int version;
+		protected readonly UInt32[] data;
+
+		public abstract int ReaderVersion { get; }
+		/// <summary>
+		/// FileStreamからReaderを作成
+		/// 不正なファイルの場合はnullを返す・例外は投げない
+		/// </summary>
+		/// <param name="fs"></param>
+		/// <returns></returns>
+		public static EraBinaryDataReader CreateReader(FileStream fs)
+		{
+			try
+			{
+				if ((fs == null) || (fs.Length < 16))
+					return null;
+				BinaryReader reader = new BinaryReader(fs, Encoding.Unicode);
+
+				if (reader.ReadUInt64() != EraBDConst.Header)
+					return null;
+				int version = (int)reader.ReadUInt32();
+				int datacount = (int)reader.ReadUInt32();
+				UInt32[] data = new UInt32[datacount];
+				for (int i = 0; i < datacount; i++)
+					data[i] = reader.ReadUInt32();
+				if (version == EraBDConst.Version1808)
+					return new EraBinaryDataReader1808(reader, version, data);
+				return null;
+			}
+			catch
+			{
+				return null;
+			}
+		}
+
+		public abstract EraSaveFileType ReadFileType();
+
+		/// <summary>
+		/// システム用の特殊処理・圧縮なし
+		/// </summary>
+		/// <returns></returns>
+		public abstract Int64 ReadInt64();
+
+		public abstract string ReadString();
+		public abstract Int64 ReadInt();
+		public abstract void ReadIntArray(Int64[] refArray, bool needInit);
+		public abstract void ReadIntArray2D(Int64[,] refArray, bool needInit);
+		public abstract void ReadIntArray3D(Int64[, ,] refArray, bool needInit);
+		public abstract void ReadStrArray(string[] refArray, bool needInit);
+		public abstract void ReadStrArray2D(string[,] refArray, bool needInit);
+		public abstract void ReadStrArray3D(string[, ,] refArray, bool needInit);
+		public abstract KeyValuePair<string, EraSaveDataType> ReadVariableCode();
+		#region IDisposable メンバ
+
+		public void Dispose()
+		{
+			if (reader != null)
+				reader.Close();
+			reader = null;
+		}
+
+		#endregion
+		public void Close()
+		{
+			Dispose();
+		}
+
+		private sealed class EraBinaryDataReader1808 : EraBinaryDataReader
+		{
+			public EraBinaryDataReader1808(BinaryReader stream, int ver, UInt32[] buf)
+				: base(stream, ver, buf)
+			{
+			}
+
+			//public bool EOF
+			//{
+			//    get
+			//    {
+			//        return (reader.BaseStream.Length == reader.BaseStream.Position);
+			//    }
+			//}
+
+			public override int ReaderVersion => 1808;
+
+			public override EraSaveFileType ReadFileType()
+			{
+				byte type = reader.ReadByte();
+				if (type >= 0 && type <= 3)
+					return (EraSaveFileType)type;
+				throw new FileEE("ファイルデータ型異常");
+			}
+
+			private Int64 m_ReadInt()
+			{
+				byte b = reader.ReadByte();
+				if (b <= Ebdb.Byte)
+					return b;
+				if (b == Ebdb.Int16)
+					return reader.ReadInt16();
+				if (b == Ebdb.Int32)
+					return reader.ReadInt32();
+				if (b == Ebdb.Int64)
+					return reader.ReadInt64();
+				throw new FileEE("バイナリデータの異常");
+			}
+
+			public override Int64 ReadInt64()
+			{
+				return reader.ReadInt64();
+			}
+
+			public override KeyValuePair<string, EraSaveDataType> ReadVariableCode()
+			{
+				EraSaveDataType type = (EraSaveDataType)reader.ReadByte();
+				if (type == EraSaveDataType.EOC || type == EraSaveDataType.EOF || type == EraSaveDataType.Separator)
+					return new KeyValuePair<string, EraSaveDataType>(null, type);
+				string key = reader.ReadString();
+				return new KeyValuePair<string, EraSaveDataType>(key, type);
+			}
+
+			//配列じゃないやつは特殊処理
+			public override Int64 ReadInt()
+			{
+				return m_ReadInt();
+			}
+
+
+			public override string ReadString()
+			{
+				return reader.ReadString();
+			}
+
+			public override void ReadIntArray(Int64[] refArray, bool needInit)
+			{
+				Int64[] oriArray = null;
+				byte b;
+				int x = 0;
+				int saveLength0 = reader.ReadInt32();
+				if (refArray == null)//読み捨て。レアケースのはず
+					refArray = new Int64[saveLength0];
+
+				int length0 = refArray.Length;
+
+				//保存されたデータの方が大きいとき。レアケースのはず
+				if (length0 < saveLength0)
+				{
+                    oriArray = refArray;
+                    //1818修正 サイズ違いの時にあふれないように/配列は最大まで確保、作業するのは重複部分だけ
+                    refArray = new Int64[Math.Max(length0, saveLength0)];
+
+                    length0 = Math.Min(length0, saveLength0);
+				}
+				while (true)
+				{
+					b = reader.ReadByte();
+					if (b == Ebdb.EoD)
+						break;
+					if (b == Ebdb.Zero)
+					{
+						int cnt = (int)m_ReadInt();
+						if (needInit)
+							for (int i = 0; i < cnt; i++)
+								refArray[x + i] = 0;
+						x += cnt;
+						continue;
+					}
+					if (b <= Ebdb.Byte)
+						refArray[x] = b;
+					else if (b == Ebdb.Int16)
+						refArray[x] = reader.ReadInt16();
+					else if (b == Ebdb.Int32)
+						refArray[x] = reader.ReadInt32();
+					else if (b == Ebdb.Int64)
+						refArray[x] = reader.ReadInt64();
+					else
+						throw new FileEE("バイナリデータの異常");
+					x++;
+				}
+				if (needInit)
+					for (; x < length0; x++)
+						refArray[x] = 0;
+				if (oriArray != null)
+				{
+					for (x = 0; x < length0; x++)
+						oriArray[x] = refArray[x];
+				}
+			}
+			public override void ReadIntArray2D(Int64[,] refArray, bool needInit)
+			{
+				Int64[,] oriArray = null;
+				byte b;
+				int x = 0;
+				int y = 0;
+				int saveLength0 = reader.ReadInt32();
+				int saveLength1 = reader.ReadInt32();
+				if (refArray == null)
+					refArray = new Int64[saveLength0, saveLength1];
+				int length0 = refArray.GetLength(0);
+				int length1 = refArray.GetLength(1);
+
+				if (length0 < saveLength0 || length1 < saveLength1)
+				{
+                    oriArray = refArray;
+                    //1818修正 サイズ違いの時にあふれないように/配列は最大まで確保、作業するのは重複部分だけ
+                    refArray = new Int64[Math.Max(length0, saveLength0), Math.Max(length1, saveLength1)];
+
+                    length0 = Math.Min(length0, saveLength0);
+                    length1 = Math.Min(length1, saveLength1);
+				}
+
+				while (true)
+				{
+					b = reader.ReadByte();
+					if (b == Ebdb.EoD)
+						break;
+					if (b == Ebdb.ZeroA1)
+					{
+						int cnt = (int)m_ReadInt();
+						if (needInit)
+							for (int i = 0; i < cnt; i++)
+								for (y = 0; y < length1; y++)
+									refArray[x + i, y] = 0;
+						x += cnt;
+						y = 0;
+						continue;
+					}
+					if (b == Ebdb.EoA1)
+					{
+						if (needInit)
+							for (; y < length1; y++)
+								refArray[x, y] = 0;
+						x++;
+						y = 0;
+						continue;
+					}
+
+					if (b == Ebdb.Zero)
+					{
+						int cnt = (int)m_ReadInt();
+						if (needInit)
+							for (int i = 0; i < cnt; i++)
+								refArray[x, y + i] = 0;
+						y += cnt;
+						continue;
+					}
+					if (b <= Ebdb.Byte)
+						refArray[x, y] = b;
+					else if (b == Ebdb.Int16)
+						refArray[x, y] = reader.ReadInt16();
+					else if (b == Ebdb.Int32)
+						refArray[x, y] = reader.ReadInt32();
+					else if (b == Ebdb.Int64)
+						refArray[x, y] = reader.ReadInt64();
+					else
+						throw new FileEE("バイナリデータの異常");
+					y++;
+				}
+				if (needInit)
+				{
+					for (; x < length0; x++)
+					{
+						for (; y < length1; y++)
+							refArray[x, y] = 0;
+						y = 0;
+					}
+				}
+				if (oriArray != null)
+				{
+					for (x = 0; x < length0; x++)
+						for (y = 0; y < length1; y++)
+							oriArray[x, y] = refArray[x, y];
+				}
+			}
+			/// <summary>
+			/// 
+			/// </summary>
+			/// <param name="refArray">データを書き出す先。読み捨てるならnull</param>
+			/// <param name="needInit">データがない部分を0で埋める必要があるか</param>
+			public override void ReadIntArray3D(Int64[, ,] refArray, bool needInit)
+			{
+				Int64[, ,] oriArray = null;
+				byte b;
+				int x = 0;
+				int y = 0;
+				int z = 0;
+				int saveLength0 = reader.ReadInt32();
+				int saveLength1 = reader.ReadInt32();
+				int saveLength2 = reader.ReadInt32();
+				if (refArray == null)
+					refArray = new Int64[saveLength0, saveLength1, saveLength2];
+				int length0 = refArray.GetLength(0);
+				int length1 = refArray.GetLength(1);
+				int length2 = refArray.GetLength(2);
+
+				if (length0 < saveLength0 || length1 < saveLength1 || length2 < saveLength2)
+				{
+					oriArray = refArray;
+                    //1818修正 サイズ違いの時にあふれないように/配列は最大まで確保、作業するのは重複部分だけ
+                    refArray = new Int64[Math.Max(length0, saveLength0), Math.Max(length1, saveLength1), Math.Max(length2, saveLength2)];
+
+                    length0 = Math.Min(length0, saveLength0);
+                    length1 = Math.Min(length1, saveLength1);
+                    length2 = Math.Min(length2, saveLength2);
+				}
+
+				while (true)
+				{
+					b = reader.ReadByte();
+					if (b == Ebdb.EoD)
+						break;
+					if (b == Ebdb.ZeroA2)//cnt分だけ空の行列が連続
+					{
+						int cnt = (int)m_ReadInt();
+						if (needInit)
+							for (int i = 0; i < cnt; i++)
+								for (y = 0; y < length1; y++)
+									for (z = 0; z < length2; z++)
+										refArray[x + i, y, z] = 0;
+						x += cnt;
+						y = 0;
+						z = 0;
+						continue;
+					}
+					if (b == Ebdb.EoA2)//行列終わりor残りが全て0
+					{
+						if (needInit)
+						{
+							for (; y < length1; y++)
+							{
+								for (; z < length2; z++)
+									refArray[x, y, z] = 0;
+								z = 0;
+							}
+						}
+						x++;
+						y = 0;
+						z = 0;
+						continue;
+					}
+
+					if (b == Ebdb.ZeroA1)//cnt分だけ空の列が連続
+					{
+						int cnt = (int)m_ReadInt();
+						if (needInit)
+							for (int i = 0; i < cnt; i++)
+								for (z = 0; z < length2; z++)
+									refArray[x, y + i, z] = 0;
+						y += cnt;
+						z = 0;
+						continue;
+					}
+					if (b == Ebdb.EoA1)//列終わりor残り全て0
+					{
+						if (needInit)
+							for (; z < length2; z++)
+								refArray[x, y, z] = 0;
+						y++;
+						z = 0;
+						continue;
+					}
+
+					if (b == Ebdb.Zero)//cnt分だけ0が連続
+					{
+						int cnt = (int)m_ReadInt();
+						if (needInit)
+							for (int i = 0; i < cnt; i++)
+								refArray[x, y, z + i] = 0;
+						z += cnt;
+						continue;
+					}
+					if (b <= Ebdb.Byte)
+						refArray[x, y, z] = b;
+					else if (b == Ebdb.Int16)
+						refArray[x, y, z] = reader.ReadInt16();
+					else if (b == Ebdb.Int32)
+						refArray[x, y, z] = reader.ReadInt32();
+					else if (b == Ebdb.Int64)
+						refArray[x, y, z] = reader.ReadInt64();
+					else
+						throw new FileEE("バイナリデータの異常");
+					z++;
+				}
+				if (needInit)
+				{
+
+					for (; x < length0; x++)
+					{
+						for (; y < length1; y++)
+						{
+							for (; z < length2; z++)
+								refArray[x, y, z] = 0;
+							z = 0;
+						}
+						y = 0;
+					}
+				}
+				if (oriArray != null)
+				{
+					for (x = 0; x < length0; x++)
+						for (y = 0; y < length1; y++)
+							for (z = 0; z < length2; z++)
+								oriArray[x, y, z] = refArray[x, y, z];
+				}
+			}
+			public override void ReadStrArray(string[] refArray, bool needInit)
+			{
+				string[] oriArray = null;
+				byte b;
+				int x = 0;
+				int saveLength0 = reader.ReadInt32();
+				if (refArray == null)//読み捨て。レアケースのはず
+					refArray = new string[saveLength0];
+
+				int length0 = refArray.Length;
+
+				//保存されたデータの方が大きいとき。レアケースのはず
+				if (length0 < saveLength0)
+				{
+                    oriArray = refArray;
+                    //1818修正 サイズ違いの時にあふれないように/配列は最大まで確保、作業するのは重複部分だけ
+                    refArray = new string[Math.Max(length0, saveLength0)];
+
+                    length0 = Math.Min(length0, saveLength0);
+				}
+				while (true)
+				{
+					b = reader.ReadByte();
+					if (b == Ebdb.EoD)
+						break;
+					if (b == Ebdb.Zero)
+					{
+						int cnt = (int)m_ReadInt();
+						if (needInit)
+							for (int i = 0; i < cnt; i++)
+								refArray[x + i] = null;
+						x += cnt;
+						continue;
+					}
+					if (b == Ebdb.String)
+						refArray[x] = ReadString();
+					else
+						throw new FileEE("バイナリデータの異常");
+					x++;
+				}
+				if (needInit)
+					for (; x < length0; x++)
+						refArray[x] = null;
+				if (oriArray != null)
+				{
+					for (x = 0; x < length0; x++)
+						oriArray[x] = refArray[x];
+				}
+			}
+			public override void ReadStrArray2D(string[,] refArray, bool needInit)
+			{
+				string[,] oriArray = null;
+				byte b;
+				int x = 0;
+				int y = 0;
+				int saveLength0 = reader.ReadInt32();
+				int saveLength1 = reader.ReadInt32();
+				if (refArray == null)
+					refArray = new string[saveLength0, saveLength1];
+				int length0 = refArray.GetLength(0);
+				int length1 = refArray.GetLength(1);
+
+				if (length0 < saveLength0 || length1 < saveLength1)
+				{
+                    oriArray = refArray;
+                    //1818修正 サイズ違いの時にあふれないように/配列は最大まで確保、作業するのは重複部分だけ
+                    refArray = new string[Math.Max(length0, saveLength0), Math.Max(length1, saveLength1)];
+
+                    length0 = Math.Min(length0, saveLength0);
+                    length1 = Math.Min(length1, saveLength1);
+				}
+
+				while (true)
+				{
+					b = reader.ReadByte();
+					if (b == Ebdb.EoD)
+						break;
+					if (b == Ebdb.ZeroA1)
+					{
+						int cnt = (int)m_ReadInt();
+						if (needInit)
+							for (int i = 0; i < cnt; i++)
+								for (y = 0; y < length1; y++)
+									refArray[x + i, y] = null;
+						x += cnt;
+						y = 0;
+						continue;
+					}
+					if (b == Ebdb.EoA1)
+					{
+						if (needInit)
+							for (; y < length1; y++)
+								refArray[x, y] = null;
+						x++;
+						y = 0;
+						continue;
+					}
+
+					if (b == Ebdb.Zero)
+					{
+						int cnt = (int)m_ReadInt();
+						if (needInit)
+							for (int i = 0; i < cnt; i++)
+								refArray[x, y + i] = null;
+						y += cnt;
+						continue;
+					}
+					if (b == Ebdb.String)
+						refArray[x, y] = ReadString();
+					else
+						throw new FileEE("バイナリデータの異常");
+					y++;
+				}
+				if (needInit)
+				{
+					for (; x < length0; x++)
+					{
+						for (; y < length1; y++)
+							refArray[x, y] = null;
+						y = 0;
+					}
+				}
+				if (oriArray != null)
+				{
+					for (x = 0; x < length0; x++)
+						for (y = 0; y < length1; y++)
+							oriArray[x, y] = refArray[x, y];
+				}
+			}
+			public override void ReadStrArray3D(string[, ,] refArray, bool needInit)
+			{
+				string[, ,] oriArray = null;
+				byte b;
+				int x = 0;
+				int y = 0;
+				int z = 0;
+				int saveLength0 = reader.ReadInt32();
+				int saveLength1 = reader.ReadInt32();
+				int saveLength2 = reader.ReadInt32();
+				if (refArray == null)
+					refArray = new string[saveLength0, saveLength1, saveLength2];
+				int length0 = refArray.GetLength(0);
+				int length1 = refArray.GetLength(1);
+				int length2 = refArray.GetLength(2);
+
+				if (length0 < saveLength0 || length1 < saveLength1 || length2 < saveLength2)
+				{
+                    oriArray = refArray;
+                    //1818修正 サイズ違いの時にあふれないように/配列は最大まで確保、作業するのは重複部分だけ
+                    refArray = new string[Math.Max(length0, saveLength0), Math.Max(length1, saveLength1), Math.Max(length2, saveLength2)];
+
+                    length0 = Math.Min(length0, saveLength0);
+                    length1 = Math.Min(length1, saveLength1);
+                    length2 = Math.Min(length2, saveLength2);
+				}
+
+				while (true)
+				{
+					b = reader.ReadByte();
+					if (b == Ebdb.EoD)
+						break;
+					if (b == Ebdb.ZeroA2)//cnt分だけ空の行列が連続
+					{
+						int cnt = (int)m_ReadInt();
+						if (needInit)
+							for (int i = 0; i < cnt; i++)
+								for (y = 0; y < length1; y++)
+									for (z = 0; z < length2; z++)
+										refArray[x + i, y, z] = null;
+						x += cnt;
+						y = 0;
+						z = 0;
+						continue;
+					}
+					if (b == Ebdb.EoA2)//行列終わりor残りが全て0
+					{
+						if (needInit)
+						{
+							for (; y < length1; y++)
+							{
+								for (; z < length2; z++)
+									refArray[x, y, z] = null;
+								z = 0;
+							}
+						}
+						x++;
+						y = 0;
+						z = 0;
+						continue;
+					}
+
+					if (b == Ebdb.ZeroA1)//cnt分だけ空の列が連続
+					{
+						int cnt = (int)m_ReadInt();
+						if (needInit)
+							for (int i = 0; i < cnt; i++)
+								for (z = 0; z < length2; z++)
+									refArray[x, y + i, z] = null;
+						y += cnt;
+						z = 0;
+						continue;
+					}
+					if (b == Ebdb.EoA1)//列終わりor残り全て0
+					{
+						if (needInit)
+							for (; z < length2; z++)
+								refArray[x, y, z] = null;
+						y++;
+						z = 0;
+						continue;
+					}
+
+					if (b == Ebdb.Zero)//cnt分だけ0が連続
+					{
+						int cnt = (int)m_ReadInt();
+						if (needInit)
+							for (int i = 0; i < cnt; i++)
+								refArray[x, y, z + i] = null;
+						z += cnt;
+						continue;
+					}
+					if (b == Ebdb.String)
+						refArray[x, y, z] = ReadString();
+					else
+						throw new FileEE("バイナリデータの異常");
+					z++;
+				}
+				if (needInit)
+				{
+					for (; x < length0; x++)
+					{
+						for (; y < length1; y++)
+						{
+							for (; z < length2; z++)
+								refArray[x, y, z] = null;
+							z = 0;
+						}
+						y = 0;
+					}
+				}
+				if (oriArray != null)
+				{
+					for (x = 0; x < length0; x++)
+						for (y = 0; y < length1; y++)
+							for (z = 0; z < length2; z++)
+								oriArray[x, y, z] = refArray[x, y, z];
+				}
+			}
+		}
+	}
+}

+ 421 - 0
NTERA/Game/Sub/EraBinaryDataWriter.cs

@@ -0,0 +1,421 @@
+using System;
+using System.IO;
+using System.Text;
+
+namespace MinorShift.Emuera.Sub
+{
+	//reader/writer共通のデータはreaderの方に
+
+
+	/// <summary>
+	/// 1808追加 新しいデータ保存形式
+	/// Reader と違ってWriterは最新の書き込み方式だけ知っていればよい
+	/// WriteHeader -> WriteFileType -> ... -> WriteEFO
+	/// </summary>
+	internal sealed class EraBinaryDataWriter : IDisposable
+	{
+		public EraBinaryDataWriter(FileStream fs)
+		{
+			writer = new BinaryWriter(fs, Encoding.Unicode);
+		}
+		BinaryWriter writer;
+		
+		public void WriteHeader()
+		{
+			writer.Write(EraBDConst.Header);
+			writer.Write(EraBDConst.Version1808);
+			writer.Write(EraBDConst.DataCount);
+			for (int i = 0; i < EraBDConst.DataCount; i++)
+			{
+				writer.Write((UInt32)0);
+			}
+		}
+
+		public void WriteFileType(EraSaveFileType type)
+		{
+			writer.Write((byte)type);
+		}
+
+
+		/// <summary>
+		/// システム用。keyなしでInt64を保存
+		/// </summary>
+		/// <param name="v"></param>
+		public void WriteInt64(Int64 v)
+		{
+			//圧縮しない
+			writer.Write(v);
+		}
+		/// <summary>
+		/// システム用。keyなしでstringを保存
+		/// </summary>
+		/// <param name="s"></param>
+		public void WriteString(string s)
+		{
+			writer.Write(s);
+		}
+
+
+		public void WriteSeparator()
+		{
+			writer.Write((byte)EraSaveDataType.Separator);
+		}
+		public void WriteEOC()
+		{
+			writer.Write((byte)EraSaveDataType.EOC);
+		}
+		public void WriteEOF()
+		{
+			writer.Write((byte)EraSaveDataType.EOF);
+		}
+
+		public void WriteWithKey(string key, object v)
+		{
+			if (v is Int64)
+			{
+				writer.Write((byte)EraSaveDataType.Int);
+				writer.Write(key);
+				writeData((Int64)v);
+			}
+			else if (v is Int64[])
+			{
+				writer.Write((byte)EraSaveDataType.IntArray);
+				writer.Write(key);
+				writeData((Int64[])v);
+			}
+			else if (v is Int64[,])
+			{
+				writer.Write((byte)EraSaveDataType.IntArray2D);
+				writer.Write(key);
+				writeData((Int64[,])v);
+			}
+			else if (v is Int64[, ,])
+			{
+				writer.Write((byte)EraSaveDataType.IntArray3D);
+				writer.Write(key);
+				writeData((Int64[, ,])v);
+			}
+			else if (v is string)
+			{
+				writer.Write((byte)EraSaveDataType.Str);
+				writer.Write(key);
+				writeData((string)v);
+			}
+			else if (v is string[])
+			{
+				writer.Write((byte)EraSaveDataType.StrArray);
+				writer.Write(key);
+				writeData((string[])v);
+			}
+			else if (v is string[,])
+			{
+				writer.Write((byte)EraSaveDataType.StrArray2D);
+				writer.Write(key);
+				writeData((string[,])v);
+			}
+			else if (v is string[, ,])
+			{
+				writer.Write((byte)EraSaveDataType.StrArray3D);
+				writer.Write(key);
+				writeData((string[, ,])v);
+			}
+		}
+
+		#region private
+
+		private void m_WriteInt(Int64 v)
+		{
+			//セーブデータ容量の爆発を避けるためにできるだけWrite(Int64)はしない
+			if (v >= 0 && v <= Ebdb.Byte)//0~207まではそのままbyteに詰め込む
+				writer.Write((byte)v);
+			else if (v >= Int16.MinValue && v <= Int16.MaxValue)//整数の範囲に応じて適当に
+			{
+				writer.Write(Ebdb.Int16);
+				writer.Write((Int16)v);
+			}
+			else if (v >= Int32.MinValue && v <= Int32.MaxValue)
+			{
+				writer.Write(Ebdb.Int32);
+				writer.Write((Int32)v);
+			}
+			else
+			{
+				writer.Write(Ebdb.Int64);
+				writer.Write(v);
+			}
+		}
+
+		private void writeData(Int64 v)
+		{
+			m_WriteInt(v);
+		}
+
+		private void writeData(Int64[] array)
+		{
+			//配列の記憶。0が連続する場合には圧縮を試みる。
+			writer.Write(array.Length);
+			int countZero = 0;//0については0が連続する数を記憶する。その他の数はそのまま記憶する。
+			for(int x = 0; x < array.Length; x++)
+			{
+				if (array[x] == 0)
+					countZero++;
+				else
+				{
+					if (countZero > 0)
+					{
+						writer.Write(Ebdb.Zero);
+						m_WriteInt(countZero);
+						countZero = 0;
+					}
+					m_WriteInt(array[x]);
+				}
+			}
+			//記憶途中で配列の残りが全部0であるなら0の数も記憶せず配列の終わりを記憶
+			writer.Write(Ebdb.EoD);
+		}
+
+		private void writeData(Int64[,] array)
+		{
+			int countZero = 0;//0については0が連続する数を記憶する。その他はそのまま記憶する。
+			int countAllZero = 0;//列の要素が全て0である列の連続する数を記憶する。列の要素に一つでも非0があるなら通常の記憶方式。
+			int length0 = array.GetLength(0);
+			int length1 = array.GetLength(1);
+			writer.Write(length0);
+			writer.Write(length1);
+			
+			for(int x = 0; x < length0; x++)
+			{
+				for(int y = 0; y < length1; y++)
+				{
+					if (array[x,y] == 0)
+						countZero++;
+					else
+					{
+						if (countAllZero > 0)
+						{
+							writer.Write(Ebdb.ZeroA1);
+							m_WriteInt(countAllZero);
+							countAllZero = 0;
+						}
+						if (countZero > 0)
+						{
+							writer.Write(Ebdb.Zero);
+							m_WriteInt(countZero);
+							countZero = 0;
+						}
+						m_WriteInt(array[x,y]);
+					}
+				}
+				if (countZero == length1)//列の要素が全部0
+					countAllZero++;
+				else
+					writer.Write(Ebdb.EoA1);//非0があるなら列終端記号を記憶
+				countZero = 0;
+			}
+			writer.Write(Ebdb.EoD);
+		}
+
+		private void writeData(Int64[, ,] array)
+		{
+			int countZero = 0;//0については0が連続する数を記憶する。その他はそのまま記憶する。
+			int countAllZero = 0;//列の要素が全て0である列の連続する数を記憶する。列の要素に一つでも非0があるなら通常の記憶方式。
+			int countAllZero2D = 0;//行列の要素が全て0である行列の・・・
+			int length0 = array.GetLength(0);
+			int length1 = array.GetLength(1);
+			int length2 = array.GetLength(2);
+			writer.Write(length0);
+			writer.Write(length1);
+			writer.Write(length2);
+			for(int x = 0; x < length0; x++)
+			{
+				for(int y = 0; y < length1; y++)
+				{
+					for(int z = 0; z < length2; z++)
+					{
+						if (array[x,y,z] == 0)
+							countZero++;
+						else
+						{
+							if (countAllZero2D > 0)
+							{
+								writer.Write(Ebdb.ZeroA2);
+								m_WriteInt(countAllZero2D);
+								countAllZero2D = 0;
+							}
+							if (countAllZero > 0)
+							{
+								writer.Write(Ebdb.ZeroA1);
+								m_WriteInt(countAllZero);
+								countAllZero = 0;
+							}
+							if (countZero > 0)
+							{
+								writer.Write(Ebdb.Zero);
+								m_WriteInt(countZero);
+								countZero = 0;
+							}
+							m_WriteInt(array[x,y,z]);
+						}
+					}
+					if (countZero == length2)
+						countAllZero++;
+					else
+						writer.Write(Ebdb.EoA1);
+					countZero = 0;
+				}
+				if (countAllZero == length1)
+					countAllZero2D++;
+				else
+					writer.Write(Ebdb.EoA2);
+				countAllZero = 0;
+			}
+			writer.Write(Ebdb.EoD);
+		}
+
+		private void writeData(string v)
+		{
+			if (v != null)
+				writer.Write(v);
+			else
+				writer.Write("");
+		}
+
+		private void writeData(string[] array)
+		{
+			int countZero = 0;
+			writer.Write(array.Length);
+			for(int x = 0; x < array.Length; x++)
+			{
+				if (array[x] == null || array[x].Length == 0)
+					countZero++;
+				else
+				{
+					if (countZero > 0)
+					{
+						writer.Write(Ebdb.Zero);
+						m_WriteInt(countZero);
+						countZero = 0;
+					}
+					writer.Write(Ebdb.String);
+					writer.Write(array[x]);
+				}
+			}
+			writer.Write(Ebdb.EoD);
+		}
+
+		private void writeData(string[,] array)
+		{
+			int countZero = 0;
+			int countAllZero = 0;
+			int length0 = array.GetLength(0);
+			int length1 = array.GetLength(1);
+			writer.Write(length0);
+			writer.Write(length1);
+			for(int x = 0; x < length0; x++)
+			{
+				for(int y = 0; y < length1; y++)
+				{
+					if (array[x,y] == null || array[x,y].Length == 0)
+						countZero++;
+					else
+					{
+						if (countAllZero > 0)
+						{
+							writer.Write(Ebdb.ZeroA1);
+							m_WriteInt(countAllZero);
+							countAllZero = 0;
+						}
+						if (countZero > 0)
+						{
+							writer.Write(Ebdb.Zero);
+							m_WriteInt(countZero);
+							countZero = 0;
+						}
+						writer.Write(Ebdb.String);
+						writer.Write(array[x,y]);
+					}
+				}
+				if (countZero == length1)
+					countAllZero++;
+				else
+					writer.Write(Ebdb.EoA1);
+				countZero = 0;
+			}
+			writer.Write(Ebdb.EoD);
+		}
+
+		private void writeData(string[, ,] array)
+		{
+			int countZero = 0;
+			int countAllZero = 0;
+			int countAllZero2D = 0;
+			int length0 = array.GetLength(0);
+			int length1 = array.GetLength(1);
+			int length2 = array.GetLength(2);
+			writer.Write(length0);
+			writer.Write(length1);
+			writer.Write(length2);
+			for(int x = 0; x < length0; x++)
+			{
+				for(int y = 0; y < length1; y++)
+				{
+					for(int z = 0; z < length2; z++)
+					{
+						if (array[x,y,z] == null || array[x,y,z].Length == 0)
+							countZero++;
+						else
+						{
+							if (countAllZero2D > 0)
+							{
+								writer.Write(Ebdb.ZeroA2);
+								m_WriteInt(countAllZero2D);
+								countAllZero2D = 0;
+							}
+							if (countAllZero > 0)
+							{
+								writer.Write(Ebdb.ZeroA1);
+								m_WriteInt(countAllZero);
+								countAllZero = 0;
+							}
+							if (countZero > 0)
+							{
+								writer.Write(Ebdb.Zero);
+								m_WriteInt(countZero);
+								countZero = 0;
+							}
+							writer.Write(Ebdb.String);
+							writer.Write(array[x,y,z]);
+						}
+					}
+					if (countZero == length2)
+						countAllZero++;
+					else
+						writer.Write(Ebdb.EoA1);
+					countZero = 0;
+				}
+				if (countAllZero == length1)
+					countAllZero2D++;
+				else
+					writer.Write(Ebdb.EoA2);
+				countAllZero = 0;
+			}
+			writer.Write(Ebdb.EoD);
+		}
+		#endregion
+		#region IDisposable メンバ
+
+		public void Dispose()
+		{
+			if (writer != null)
+				writer.Close();
+			writer = null;
+		}
+
+		#endregion
+		public void Close()
+		{
+			Dispose();
+		}
+
+	}
+}

+ 754 - 0
NTERA/Game/Sub/EraDataStream.cs

@@ -0,0 +1,754 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+
+namespace MinorShift.Emuera.Sub
+{
+
+	//難読化用属性。enum.ToString()やenum.Parse()を行うなら(Exclude=true)にすること。
+	[Obfuscation(Exclude = false)]
+	internal enum EraDataState
+	{
+		OK = 0,//ロード可能
+		FILENOTFOUND = 1,//ファイルが存在せず
+		GAME_ERROR = 2,//ゲームが違う
+		VIRSION_ERROR = 3,//バージョンが違う
+		ETC_ERROR = 4//その他のエラー
+
+	}
+
+	internal sealed class EraDataResult
+	{
+		public EraDataState State = EraDataState.OK;
+		public string DataMes = "";
+	}
+
+	/// <summary>
+	/// セーブデータ読み取り
+	/// </summary>
+	internal sealed class EraDataReader : IDisposable
+	{
+		//public EraDataReader(string filepath)
+		//{
+		//    file = new FileStream(filepath, FileMode.Open, FileAccess.Read);
+		//    reader = new StreamReader(file, Config.Encode);
+		//}
+		public EraDataReader(FileStream file)
+		{
+			this.file = file;
+			file.Seek(0, SeekOrigin.Begin);
+			reader = new StreamReader(file, Config.Encode);
+		}
+		FileStream file;
+		StreamReader reader;
+		public const string FINISHER = "__FINISHED";
+		public const string EMU_1700_START = "__EMUERA_STRAT__";
+		public const string EMU_1708_START = "__EMUERA_1708_STRAT__";
+		public const string EMU_1729_START = "__EMUERA_1729_STRAT__";
+		public const string EMU_1803_START = "__EMUERA_1803_STRAT__";
+		public const string EMU_1808_START = "__EMUERA_1808_STRAT__";
+		public const string EMU_SEPARATOR = "__EMU_SEPARATOR__";
+		#region eramaker
+		public string ReadString()
+		{
+			if (reader == null)
+				throw new FileEE("無効なストリームです");
+			string str = reader.ReadLine();
+			if (str == null)
+				throw new FileEE("読み取るべき文字列がありません");
+			return str;
+		}
+
+		public Int64 ReadInt64()
+		{
+			if (reader == null)
+				throw new FileEE("無効なストリームです");
+			Int64 ret = 0;
+			string str = reader.ReadLine();
+			if (str == null)
+				throw new FileEE("読み取るべき数値がありません");
+			if (!Int64.TryParse(str, out ret))
+				throw new FileEE("数値として認識できません");
+			return ret;
+		}
+
+
+		public void ReadInt64Array(Int64[] array)
+		{
+			if (reader == null)
+				throw new FileEE("無効なストリームです");
+			if (array == null)
+				throw new FileEE("無効な配列が渡されました");
+			int i = -1;
+			string str = null;
+			Int64 integer = 0;
+			i = -1;
+			while (true)
+			{
+				i++;
+				str = reader.ReadLine();
+				if (str == null)
+					throw new FileEE("予期しないセーブデータの終端です");
+				if (str.Equals(FINISHER, StringComparison.Ordinal))
+					break;
+				if (i >= array.Length)//配列を超えて保存されていても動じないで読み飛ばす。
+					continue;
+				if (!Int64.TryParse(str, out integer))
+					throw new FileEE("数値として認識できません");
+				array[i] = integer;
+			}
+			for (; i < array.Length; i++)//保存されている値が無いなら0に初期化
+				array[i] = 0;
+		}
+
+		public void ReadStringArray(string[] array)
+		{
+			if (reader == null)
+				throw new FileEE("無効なストリームです");
+			if (array == null)
+				throw new FileEE("無効な配列が渡されました");
+			int i = -1;
+			string str = null;
+			i = -1;
+			while (true)
+			{
+				i++;
+				str = reader.ReadLine();
+				if (str == null)
+					throw new FileEE("予期しないセーブデータの終端です");
+				if (str.Equals(FINISHER, StringComparison.Ordinal))
+					break;
+				if (i >= array.Length)//配列を超えて保存されていても動じないで読み飛ばす。
+					continue;
+				array[i] = str;
+			}
+			for (; i < array.Length; i++)//保存されている値が無いなら""に初期化
+				array[i] = "";
+		}
+		#endregion
+		#region Emuera
+		int emu_version = -1;
+		public int DataVersion => emu_version;
+
+		public bool SeekEmuStart()
+		{
+
+			if (reader == null)
+				throw new FileEE("無効なストリームです");
+			if (reader.EndOfStream)
+				return false;
+			while (true)
+			{
+				string str = reader.ReadLine();
+				if (str == null)
+					return false;
+				if (str.Equals(EMU_1700_START, StringComparison.Ordinal))
+				{
+					emu_version = 1700;
+					return true;
+				}
+				if (str.Equals(EMU_1708_START, StringComparison.Ordinal))
+				{
+					emu_version = 1708;
+					return true;
+				}
+				if (str.Equals(EMU_1729_START, StringComparison.Ordinal))
+				{
+					emu_version = 1729;
+					return true;
+				}
+				if (str.Equals(EMU_1803_START, StringComparison.Ordinal))
+				{
+					emu_version = 1803;
+					return true;
+				}
+				if (str.Equals(EMU_1808_START, StringComparison.Ordinal))
+				{
+					emu_version = 1808;
+					return true;
+				}
+			}
+		}
+
+		public Dictionary<string, string> ReadStringExtended()
+		{
+			if (reader == null)
+				throw new FileEE("無効なストリームです");
+			Dictionary<string, string> strList = new Dictionary<string, string>();
+			string str = null;
+			while (true)
+			{
+				str = reader.ReadLine();
+				if (str == null)
+					throw new FileEE("予期しないセーブデータの終端です");
+				if (str.Equals(FINISHER, StringComparison.Ordinal))
+					throw new FileEE("セーブデータの形式が不正です");
+				if (str.Equals(EMU_SEPARATOR, StringComparison.Ordinal))
+					break;
+				int index = str.IndexOf(':');
+				if (index < 0)
+					throw new FileEE("セーブデータの形式が不正です");
+				string key = str.Substring(0, index);
+				string value = str.Substring(index + 1, str.Length - index - 1);
+				if (!strList.ContainsKey(key))
+					strList.Add(key, value);
+			}
+			return strList;
+		}
+		public Dictionary<string, Int64> ReadInt64Extended()
+		{
+			if (reader == null)
+				throw new FileEE("無効なストリームです");
+			Dictionary<string, Int64> intList = new Dictionary<string, Int64>();
+			string str = null;
+			while (true)
+			{
+				str = reader.ReadLine();
+				if (str == null)
+					throw new FileEE("予期しないセーブデータの終端です");
+				if (str.Equals(FINISHER, StringComparison.Ordinal))
+					throw new FileEE("セーブデータの形式が不正です");
+				if (str.Equals(EMU_SEPARATOR, StringComparison.Ordinal))
+					break;
+				int index = str.IndexOf(':');
+				if (index < 0)
+					throw new FileEE("セーブデータの形式が不正です");
+				string key = str.Substring(0, index);
+				string valueStr = str.Substring(index + 1, str.Length - index - 1);
+				Int64 value = 0;
+				if (!Int64.TryParse(valueStr, out value))
+					throw new FileEE("数値として認識できません");
+				if (!intList.ContainsKey(key))
+					intList.Add(key, value);
+			}
+			return intList;
+		}
+
+		public Dictionary<string, List<Int64>> ReadInt64ArrayExtended()
+		{
+			if (reader == null)
+				throw new FileEE("無効なストリームです");
+			Dictionary<string, List<Int64>> ret = new Dictionary<string, List<Int64>>();
+			string str = null;
+			while (true)
+			{
+				str = reader.ReadLine();
+				if (str == null)
+					throw new FileEE("予期しないセーブデータの終端です");
+				if (str.Equals(FINISHER, StringComparison.Ordinal))
+					throw new FileEE("セーブデータの形式が不正です");
+				if (str.Equals(EMU_SEPARATOR, StringComparison.Ordinal))
+					break;
+				string key = str;
+				List<Int64> valueList = new List<Int64>();
+				while (true)
+				{
+					str = reader.ReadLine();
+					if (str == null)
+						throw new FileEE("予期しないセーブデータの終端です");
+					if (str.Equals(EMU_SEPARATOR, StringComparison.Ordinal))
+						throw new FileEE("セーブデータの形式が不正です");
+					if (str.Equals(FINISHER, StringComparison.Ordinal))
+						break;
+					Int64 value = 0;
+					if (!Int64.TryParse(str, out value))
+						throw new FileEE("数値として認識できません");
+					valueList.Add(value);
+				}
+				if (!ret.ContainsKey(key))
+					ret.Add(key, valueList);
+			}
+			return ret;
+		}
+
+		public Dictionary<string, List<string>> ReadStringArrayExtended()
+		{
+			if (reader == null)
+				throw new FileEE("無効なストリームです");
+			Dictionary<string, List<string>> ret = new Dictionary<string, List<string>>();
+			string str = null;
+			while (true)
+			{
+				str = reader.ReadLine();
+				if (str == null)
+					throw new FileEE("予期しないセーブデータの終端です");
+				if (str.Equals(FINISHER, StringComparison.Ordinal))
+					throw new FileEE("セーブデータの形式が不正です");
+				if (str.Equals(EMU_SEPARATOR, StringComparison.Ordinal))
+					break;
+				string key = str;
+				List<string> valueList = new List<string>();
+				while (true)
+				{
+					str = reader.ReadLine();
+					if (str == null)
+						throw new FileEE("予期しないセーブデータの終端です");
+					if (str.Equals(EMU_SEPARATOR, StringComparison.Ordinal))
+						throw new FileEE("セーブデータの形式が不正です");
+					if (str.Equals(FINISHER, StringComparison.Ordinal))
+						break;
+					valueList.Add(str);
+				}
+				if (!ret.ContainsKey(key))
+					ret.Add(key, valueList);
+			}
+			return ret;
+		}
+
+		public Dictionary<string, List<Int64[]>> ReadInt64Array2DExtended()
+		{
+			if (reader == null)
+				throw new FileEE("無効なストリームです");
+			Dictionary<string, List<Int64[]>> ret = new Dictionary<string, List<Int64[]>>();
+			if (emu_version < 1708)
+				return ret;
+			string str = null;
+			while (true)
+			{
+				str = reader.ReadLine();
+				if (str == null)
+					throw new FileEE("予期しないセーブデータの終端です");
+				if (str.Equals(FINISHER, StringComparison.Ordinal))
+					throw new FileEE("セーブデータの形式が不正です");
+				if (str.Equals(EMU_SEPARATOR, StringComparison.Ordinal))
+					break;
+				string key = str;
+				List<Int64[]> valueList = new List<Int64[]>();
+				while (true)
+				{
+					str = reader.ReadLine();
+					if (str == null)
+						throw new FileEE("予期しないセーブデータの終端です");
+					if (str.Equals(EMU_SEPARATOR, StringComparison.Ordinal))
+						throw new FileEE("セーブデータの形式が不正です");
+					if (str.Equals(FINISHER, StringComparison.Ordinal))
+						break;
+					if (str.Length == 0)
+					{
+						valueList.Add(new Int64[0]);
+						continue;
+					}
+					string[] tokens = str.Split(',');
+					Int64[] intTokens = new Int64[tokens.Length];
+
+					for (int x = 0; x < tokens.Length; x++)
+						if (!Int64.TryParse(tokens[x], out intTokens[x]))
+							throw new FileEE(tokens[x] + "は数値として認識できません");
+					valueList.Add(intTokens);
+				}
+				if (!ret.ContainsKey(key))
+					ret.Add(key, valueList);
+			}
+			return ret;
+		}
+
+		public Dictionary<string, List<string[]>> ReadStringArray2DExtended()
+		{
+			if (reader == null)
+				throw new FileEE("無効なストリームです");
+			Dictionary<string, List<string[]>> ret = new Dictionary<string, List<string[]>>();
+			if (emu_version < 1708)
+				return ret;
+			string str = null;
+			while (true)
+			{
+				str = reader.ReadLine();
+				if (str == null)
+					throw new FileEE("予期しないセーブデータの終端です");
+				if (str.Equals(FINISHER, StringComparison.Ordinal))
+					throw new FileEE("セーブデータの形式が不正です");
+				if (str.Equals(EMU_SEPARATOR, StringComparison.Ordinal))
+					break;
+				throw new FileEE("StringArray2Dのロードには対応していません");
+			}
+			return ret;
+		}
+
+		public Dictionary<string, List<List<Int64[]>>> ReadInt64Array3DExtended()
+		{
+			if (reader == null)
+				throw new FileEE("無効なストリームです");
+			Dictionary<string, List<List<Int64[]>>> ret = new Dictionary<string, List<List<Int64[]>>>();
+			if (emu_version < 1729)
+				return ret;
+			string str = null;
+			while (true)
+			{
+				str = reader.ReadLine();
+				if (str == null)
+					throw new FileEE("予期しないセーブデータの終端です");
+				if (str.Equals(FINISHER, StringComparison.Ordinal))
+					throw new FileEE("セーブデータの形式が不正です");
+				if (str.Equals(EMU_SEPARATOR, StringComparison.Ordinal))
+					break;
+				string key = str;
+				List<List<Int64[]>> valueList = new List<List<Int64[]>>();
+				while (true)
+				{
+					str = reader.ReadLine();
+					if (str == null)
+						throw new FileEE("予期しないセーブデータの終端です");
+					if (str.Equals(EMU_SEPARATOR, StringComparison.Ordinal))
+						throw new FileEE("セーブデータの形式が不正です");
+					if (str.Equals(FINISHER, StringComparison.Ordinal))
+						break;
+					if (str.Contains("{"))
+					{
+						List<Int64[]> tokenList = new List<long[]>();
+						while (true)
+						{
+							str = reader.ReadLine();
+							if (str == "}")
+								break;
+							if (str.Length == 0)
+							{
+								tokenList.Add(new Int64[0]);
+								continue;
+							}
+							string[] tokens = str.Split(',');
+							Int64[] intTokens = new Int64[tokens.Length];
+
+							for (int x = 0; x < tokens.Length; x++)
+								if (!Int64.TryParse(tokens[x], out intTokens[x]))
+									throw new FileEE(tokens[x] + "は数値として認識できません");
+							tokenList.Add(intTokens);
+						}
+						valueList.Add(tokenList);
+					}
+				}
+				if (!ret.ContainsKey(key))
+					ret.Add(key, valueList);
+			}
+			return ret;
+		}
+
+		public Dictionary<string, List<List<string[]>>> ReadStringArray3DExtended()
+		{
+			if (reader == null)
+				throw new FileEE("無効なストリームです");
+			Dictionary<string, List<List<string[]>>> ret = new Dictionary<string, List<List<string[]>>>();
+			if (emu_version < 1729)
+				return ret;
+			string str = null;
+			while (true)
+			{
+				str = reader.ReadLine();
+				if (str == null)
+					throw new FileEE("予期しないセーブデータの終端です");
+				if (str.Equals(FINISHER, StringComparison.Ordinal))
+					throw new FileEE("セーブデータの形式が不正です");
+				if (str.Equals(EMU_SEPARATOR, StringComparison.Ordinal))
+					break;
+				throw new FileEE("StringArray2Dのロードには対応していません");
+			}
+			return ret;
+		}
+
+		#endregion
+		#region IDisposable メンバ
+
+		public void Dispose()
+		{
+			if (reader != null)
+				reader.Close();
+			else if (file != null)
+				file.Close();
+			file = null;
+			reader = null;
+		}
+
+		#endregion
+		public void Close()
+		{
+			Dispose();
+		}
+
+	}
+
+	/// <summary>
+	/// セーブデータ書き込み
+	/// </summary>
+	internal sealed class EraDataWriter : IDisposable
+	{
+		//public EraDataWriter(string filepath)
+		//{
+		//    FileStream file = new FileStream(filepath, FileMode.Create, FileAccess.Write);
+		//    writer = new StreamWriter(file, Config.SaveEncode);
+		//    //writer = new StreamWriter(filepath, false, Config.SaveEncode);
+		//}
+		public EraDataWriter(FileStream file)
+		{
+			this.file = file;
+			writer = new StreamWriter(file, Config.SaveEncode);
+		}
+		
+		public const string FINISHER = EraDataReader.FINISHER;
+		public const string EMU_START = EraDataReader.EMU_1808_START;
+		public const string EMU_SEPARATOR = EraDataReader.EMU_SEPARATOR;
+		FileStream file;
+		StreamWriter writer;
+		#region eramaker
+		public void Write(Int64 integer)
+		{
+			if (writer == null)
+				throw new FileEE("無効なストリームです");
+			writer.WriteLine(integer.ToString());
+		}
+
+
+		public void Write(string str)
+		{
+			if (writer == null)
+				throw new FileEE("無効なストリームです");
+			if (str == null)
+				writer.WriteLine("");
+			else
+				writer.WriteLine(str);
+		}
+
+		public void Write(Int64[] array)
+		{
+			if (writer == null)
+				throw new FileEE("無効なストリームです");
+			if (array == null)
+				throw new FileEE("無効な配列が渡されました");
+			int count = -1;
+			for (int i = 0; i < array.Length; i++)
+				if (array[i] != 0)
+					count = i;
+			count++;
+			for (int i = 0; i < count; i++)
+				writer.WriteLine(array[i].ToString());
+			writer.WriteLine(FINISHER);
+		}
+		public void Write(string[] array)
+		{
+			if (writer == null)
+				throw new FileEE("無効なストリームです");
+			if (array == null)
+				throw new FileEE("無効な配列が渡されました");
+			int count = -1;
+			for (int i = 0; i < array.Length; i++)
+				if (!string.IsNullOrEmpty(array[i]))
+					count = i;
+			count++;
+			for (int i = 0; i < count; i++)
+			{
+				if (array[i] == null)
+					writer.WriteLine("");
+				else
+					writer.WriteLine(array[i]);
+			}
+			writer.WriteLine(FINISHER);
+		}
+		#endregion
+		#region Emuera
+
+		public void EmuStart()
+		{
+			if (writer == null)
+				throw new FileEE("無効なストリームです");
+			writer.WriteLine(EMU_START);
+		}
+		public void EmuSeparete()
+		{
+			if (writer == null)
+				throw new FileEE("無効なストリームです");
+			writer.WriteLine(EMU_SEPARATOR);
+		}
+
+		public void WriteExtended(string key, Int64 value)
+		{
+			if (writer == null)
+				throw new FileEE("無効なストリームです");
+			if (value == 0)
+				return;
+			writer.WriteLine("{0}:{1}", key, value);
+		}
+
+		public void WriteExtended(string key, string value)
+		{
+			if (writer == null)
+				throw new FileEE("無効なストリームです");
+			if (string.IsNullOrEmpty(value))
+				return;
+			writer.WriteLine("{0}:{1}", key, value);
+		}
+
+
+		public void WriteExtended(string key, Int64[] array)
+		{
+			if (writer == null)
+				throw new FileEE("無効なストリームです");
+			if (array == null)
+				throw new FileEE("無効な配列が渡されました");
+			int count = -1;
+			for (int i = 0; i < array.Length; i++)
+				if (array[i] != 0)
+					count = i;
+			count++;
+			if (count == 0)
+				return;
+			writer.WriteLine(key);
+			for (int i = 0; i < count; i++)
+				writer.WriteLine(array[i].ToString());
+			writer.WriteLine(FINISHER);
+		}
+		public void WriteExtended(string key, string[] array)
+		{
+			if (writer == null)
+				throw new FileEE("無効なストリームです");
+			if (array == null)
+				throw new FileEE("無効な配列が渡されました");
+			int count = -1;
+			for (int i = 0; i < array.Length; i++)
+				if (!string.IsNullOrEmpty(array[i]))
+					count = i;
+			count++;
+			if (count == 0)
+				return;
+			writer.WriteLine(key);
+			for (int i = 0; i < count; i++)
+			{
+				if (array[i] == null)
+					writer.WriteLine("");
+				else
+					writer.WriteLine(array[i]);
+			}
+			writer.WriteLine(FINISHER);
+		}
+
+		public void WriteExtended(string key, Int64[,] array2D)
+		{
+			if (writer == null)
+				throw new FileEE("無効なストリームです");
+			if (array2D == null)
+				throw new FileEE("無効な配列が渡されました");
+			int countX = 0;
+			int length0 = array2D.GetLength(0);
+			int length1 = array2D.GetLength(1);
+			int[] countY = new int[length0];
+			for (int x = 0; x < length0; x++)
+			{
+				for (int y = 0; y < length1; y++)
+				{
+					if (array2D[x, y] != 0)
+					{
+						countX = x + 1;
+						countY[x] = y + 1;
+					}
+				}
+			}
+			if (countX == 0)
+				return;
+			writer.WriteLine(key);
+			for (int x = 0; x < countX; x++)
+			{
+				if (countY[x] == 0)
+				{
+					writer.WriteLine("");
+					continue;
+				}
+				StringBuilder builder = new StringBuilder("");
+				for (int y = 0; y < countY[x]; y++)
+				{
+					builder.Append(array2D[x, y].ToString());
+					if (y != countY[x] - 1)
+						builder.Append(",");
+				}
+				writer.WriteLine(builder.ToString());
+			}
+			writer.WriteLine(FINISHER);
+		}
+
+		public void WriteExtended(string key, string[,] array2D)
+		{
+			throw new NotImplementedException("まだ実装してないよ");
+		}
+
+		public void WriteExtended(string key, Int64[, ,] array3D)
+		{
+			if (writer == null)
+				throw new FileEE("無効なストリームです");
+			if (array3D == null)
+				throw new FileEE("無効な配列が渡されました");
+			int countX = 0;
+			int length0 = array3D.GetLength(0);
+			int length1 = array3D.GetLength(1);
+			int length2 = array3D.GetLength(2);
+			int[] countY = new int[length0];
+			int[,] countZ = new int[length0, length1];
+			for (int x = 0; x < length0; x++)
+			{
+				for (int y = 0; y < length1; y++)
+				{
+					for (int z = 0; z < length2; z++)
+					{
+						if (array3D[x, y, z] != 0)
+						{
+							countX = x + 1;
+							countY[x] = y + 1;
+							countZ[x, y] = z + 1;
+						}
+					}
+				}
+			}
+			if (countX == 0)
+				return;
+			writer.WriteLine(key);
+			for (int x = 0; x < countX; x++)
+			{
+				writer.WriteLine(x + "{");
+				if (countY[x] == 0)
+				{
+					writer.WriteLine("}");
+					continue;
+				}
+				for (int y = 0; y < countY[x]; y++)
+				{
+					StringBuilder builder = new StringBuilder("");
+					if (countZ[x, y] == 0)
+					{
+						writer.WriteLine("");
+						continue;
+					}
+					for (int z = 0; z < countZ[x, y]; z++)
+					{
+						builder.Append(array3D[x, y, z].ToString());
+						if (z != countZ[x, y] - 1)
+							builder.Append(",");
+					}
+					writer.WriteLine(builder.ToString());
+				}
+				writer.WriteLine("}");
+			}
+			writer.WriteLine(FINISHER);
+		}
+
+		public void WriteExtended(string key, string[, ,] array2D)
+		{
+			throw new NotImplementedException("まだ実装してないよ");
+		}
+		#endregion
+
+		#region IDisposable メンバ
+
+		public void Dispose()
+		{
+			if (writer != null)
+				writer.Close();
+			else if (file != null)
+				file.Close();
+			writer = null;
+			file = null;
+		}
+
+		#endregion
+		public void Close()
+		{
+			Dispose();
+		}
+	}
+}

+ 167 - 0
NTERA/Game/Sub/EraStreamReader.cs

@@ -0,0 +1,167 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace MinorShift.Emuera.Sub
+{
+	internal sealed class EraStreamReader : IDisposable
+	{
+		public EraStreamReader(bool useRename)
+		{
+			this.useRename = useRename;
+		}
+
+		string filepath;
+		string filename;
+		bool useRename;
+		int curNo;
+		int nextNo;
+		StreamReader reader;
+		FileStream stream;
+
+		public bool Open(string path)
+		{
+			return Open(path, Path.GetFileName(path));
+		}
+
+		public bool Open(string path, string name)
+		{
+			//そんなお行儀の悪いことはしていない
+			//if (disposed)
+			//    throw new ExeEE("破棄したオブジェクトを再利用しようとした");
+			//if ((reader != null) || (stream != null) || (filepath != null))
+			//    throw new ExeEE("使用中のオブジェクトを別用途に再利用しようとした");
+			filepath = path;
+			filename = name;
+			nextNo = 0;
+			curNo = 0;
+			try
+			{
+				stream = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+				reader = new StreamReader(stream, Config.Encode);
+			}
+			catch
+			{
+				Dispose();
+				return false;
+			}
+			return true;
+		}
+
+		public string ReadLine()
+		{
+			nextNo++;
+			curNo = nextNo;
+			return reader.ReadLine();
+		}
+
+		/// <summary>
+		/// 次の有効な行を読む。LexicalAnalyzer経由でConfigを参照するのでConfig完成までつかわないこと。
+		/// </summary>
+		public StringStream ReadEnabledLine()
+		{
+			string line = null;
+			StringStream st = null;
+			curNo = nextNo;
+			while (true)
+			{
+				line = reader.ReadLine();
+				curNo++;
+				nextNo++;
+				if (line == null)
+					return null;
+				if (line.Length == 0)
+					continue;
+
+				if (useRename && (line.IndexOf("[[") >= 0) && (line.IndexOf("]]") >= 0))
+				{
+					foreach (KeyValuePair<string, string> pair in ParserMediator.RenameDic)
+						line = line.Replace(pair.Key, pair.Value);
+				}
+				st = new StringStream(line);
+				LexicalAnalyzer.SkipWhiteSpace(st);
+				if (st.EOS)
+					continue;
+				if (st.Current == '}')
+					throw new CodeEE("予期しない行連結終端記号'}'が見つかりました");
+				if (st.Current == '{')
+				{
+					if (line.Trim() != "{")
+						throw new CodeEE("行連結始端記号'{'の行に'{'以外の文字を含めることはできません");
+					break;
+				}
+				return st;
+			}
+			//curNoはこの後加算しない(始端記号の行を行番号とする)
+			StringBuilder b = new StringBuilder();
+			while (true)
+			{
+				line = reader.ReadLine();
+				nextNo++;
+				if (line == null)
+				{
+					throw new CodeEE("行連結始端記号'{'が使われましたが終端記号'}'が見つかりません");
+				}
+
+				if (useRename && (line.IndexOf("[[") >= 0) && (line.IndexOf("]]") >= 0))
+				{
+					foreach (KeyValuePair<string, string> pair in ParserMediator.RenameDic)
+						line = line.Replace(pair.Key, pair.Value);
+				}
+				string test = line.TrimStart();
+				if (test.Length > 0)
+				{
+					if (test[0] == '}')
+					{
+						if (test.Trim() != "}")
+							throw new CodeEE("行連結終端記号'}'の行に'}'以外の文字を含めることはできません");
+						break;
+					}
+					if (test[0] == '{')
+						throw new CodeEE("予期しない行連結始端記号'{'が見つかりました");
+				}
+				b.Append(line);
+				b.Append(" ");
+			}
+			st = new StringStream(b.ToString());
+			LexicalAnalyzer.SkipWhiteSpace(st);
+			return st;
+		}
+
+		/// <summary>
+		/// 直前に読んだ行の行番号
+		/// </summary>
+		public int LineNo => curNo;
+
+		public string Filename => filename;
+		//public string Filepath
+		//{
+		//    get
+		//    {
+		//        return filepath;
+		//    }
+		//}
+
+		public void Close() { Dispose(); }
+		bool disposed;
+		#region IDisposable メンバ
+
+		public void Dispose()
+		{
+			if (disposed)
+				return;
+			if (reader != null)
+				reader.Close();
+			else if (stream != null)
+				stream.Close();
+			filepath = null;
+			filename = null;
+			reader = null;
+			stream = null;
+			disposed = true;
+		}
+
+		#endregion
+	}
+}

+ 1260 - 0
NTERA/Game/Sub/LexicalAnalyzer.cs

@@ -0,0 +1,1260 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Threading;
+using MinorShift.Emuera.GameData;
+using MinorShift.Emuera.GameData.Expression;
+using NTERA.Interop;
+
+namespace MinorShift.Emuera.Sub
+{
+	enum LexEndWith
+	{
+		//いずれにせよEoLで強制終了
+		None = 0,
+		EoL,//常に最後まで解析
+		Operator,//演算子を見つけたら終了。代入式の左辺
+		Question,//三項演算子?により終了。\@~~?~~#~~\@
+		Percent,//%により終了。%~~%
+		RightCurlyBrace,//}により終了。{~~}
+		Comma,//,により終了。TIMES第一引数
+		//Single,//Identifier一つで終了//1807 Single削除
+		GreaterThan//'>'により終了。Htmlタグ解析
+	}
+
+	enum FormStrEndWith
+	{
+		//いずれにせよEoLで強制終了
+		None = 0,
+		EoL,//常に最後まで解析
+		DoubleQuotation,//"で終了。@"~~"
+		Sharp,//#で終了。\@~~?~~#~~\@ の一つ目
+		YenAt,//\@で終了。\@~~?~~#~~\@ の二つ目
+		Comma,//,により終了。ANY_FORM引数
+		LeftParenthesis_Bracket_Comma_Semicolon//[または(または,または;により終了。CALLFORM系の関数名部分。
+	}
+
+	enum StrEndWith
+	{
+		//いずれにせよEoLで強制終了
+		None = 0,
+		EoL,//常に最後まで解析
+		SingleQuotation,//"で終了。'~~'
+		DoubleQuotation,//"で終了。"~~"
+		Comma,//,により終了。PRINTV'~~,
+		LeftParenthesis_Bracket_Comma_Semicolon//[または(または,または;により終了。関数名部分。
+	}
+
+	enum LexAnalyzeFlag
+	{
+		None = 0,
+		AnalyzePrintV = 1,
+		AllowAssignment = 2,
+		AllowSingleQuotationStr = 4
+	}
+
+	/// <summary>
+	/// 1756 TokenReaderより改名
+	/// Lexicalといいつつ構文解析を含む
+	/// </summary>
+	internal static class LexicalAnalyzer
+	{
+
+		const int MAX_EXPAND_MACRO = 100;
+		//readonly static IList<char> operators = new char[] { '+', '-', '*', '/', '%', '=', '!', '<', '>', '|', '&', '^', '~', '?', '#' };
+		//readonly static IList<char> whiteSpaces = new char[] { ' ', ' ', '\t' };
+		//readonly static IList<char> endOfExpression = new char[] { ')', '}', ']', ',', ':' };
+		//readonly static IList<char> startOfExpression = new char[] { '(' };
+		//readonly static IList<char> stringToken = new char[] { '\"', };
+		//readonly static IList<char> stringFormToken = new char[] { '@', };
+		//readonly static IList<char> etcSymbol = new char[] { '[', '{', '$', '\\', };
+		//readonly static IList<char> decimalDigits = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', };
+		static readonly IList<char> hexadecimalDigits = new[] { 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+	//1819 正規表現使うとやや遅い。いずれdoubleにも対応させたい。そのうち考える
+		//readonly static Regex DigitsReg = new Regex("" +
+		//	"(" +
+		//	"((?<simple>[-]?[0-9]+)([^.xXbBeEpP]|$))" +
+		//	"|(" +
+		//	"(0(x|X)(?<hex>[0-9a-fA-F]+))|"+
+		//	"(0(b|B)(?<bin>[01]+))|"+
+		//	"(" + //base10
+		//	"(?<integer>[-]?[0-9]*(?<double>[.][0-9])?)" +
+		//	"(((p|P)(?<exp2>[0-9]+))|" +
+		//	"((e|E)(?<exp10>[0-9]+)))?" +
+		//	")"+
+		//	"))"
+		//	, RegexOptions.Compiled);
+		//readonly static Regex idReg = new Regex(@"[^][ \t+*/%=!<>|&^~?#(){},:$\\'""@.; -]+", RegexOptions.Compiled);
+		//public static Int64 ReadInt64(StringStream st, bool retZero)
+		//{
+		//	Match m = DigitsReg.Match(st.RowString, st.CurrentPosition);
+		//	string numstr = m.Groups["simple"].Value;
+		//	if (numstr.Length > 0)
+		//	{
+		//		st.Jump(numstr.Length);
+		//		return Convert.ToInt64(numstr, 10);
+		//	}
+		//	st.Jump(m.Length);
+		//	if (m.Groups["bin"].Length > 0)
+		//		return Convert.ToInt64(m.Groups["bin"].Value, 2);
+		//	if(m.Groups["hex"].Length > 0)
+		//		return Convert.ToInt64(m.Groups["hex"].Value, 16);
+		//	numstr = m.Groups["number"].Value;
+		//	if (numstr.Length > 0)
+		//	{
+		//		int exp = 0;
+		//		string exp2 = m.Groups["exp2"].Value;
+		//		string exp10 = m.Groups["exp10"].Value;
+		//		if(m.Groups["double"].Length == 0 && exp2.Length == 0 && exp10.Length == 0)
+		//		{
+		//			return Convert.ToInt64(numstr,10);
+		//		}
+		//		double d = Convert.ToDouble(numstr);
+		//		if (exp2.Length > 0)
+		//		{
+		//			exp = Convert.ToInt32(exp2, 10);
+		//			d = d * Math.Pow(2, exp);
+		//		}
+		//		else if (exp10.Length > 0)
+		//		{
+		//			exp = Convert.ToInt32(exp10, 10);
+		//			d = d * Math.Pow(10, exp);
+		//		}
+		//		return ((Int64)(d + 0.49));
+		//	}
+		//	throw new CodeEE("数字で始まるトークンが適切でありません");
+		//}
+
+
+
+		public static bool UseMacro = true;
+		#region read
+		public static Int64 ReadInt64(StringStream st, bool retZero)
+		{
+			Int64 significand = 0;
+			int expBase = 0;
+			int exponent = 0;
+			int stStartPos = st.CurrentPosition;
+			int stEndPos = st.CurrentPosition;
+			int fromBase = 10;
+			if (st.Current == '0')
+			{
+				char c = st.Next;
+				if ((c == 'x') || (c == 'X'))
+				{
+					fromBase = 16;
+					st.ShiftNext();
+					st.ShiftNext();
+				}
+				else if ((c == 'b') || (c == 'B'))
+				{
+					fromBase = 2;
+					st.ShiftNext();
+					st.ShiftNext();
+				}
+				//8進法は互換性の問題から採用しない。
+				//else if (dchar.IsDigit(c))
+				//{
+				//    fromBase = 8;
+				//    st.ShiftNext();
+				//}
+			}
+			if (retZero && st.Current != '+' && st.Current != '-' && !char.IsDigit(st.Current))
+			{
+				if (fromBase != 16)
+					return 0;
+				if (!hexadecimalDigits.Contains(st.Current))
+					return 0;
+			}
+			significand = readDigits(st, fromBase);
+			if ((st.Current == 'p') || (st.Current == 'P'))
+				expBase = 2;
+			else if ((st.Current == 'e') || (st.Current == 'E'))
+				expBase = 10;
+			if (expBase != 0)
+			{
+				st.ShiftNext();
+				unchecked { exponent = (int)readDigits(st, fromBase); }
+			}
+			stEndPos = st.CurrentPosition;
+			if ((expBase != 0) && (exponent != 0))
+			{
+
+				double d = significand * Math.Pow(expBase, exponent);
+				if ((double.IsNaN(d)) || (double.IsInfinity(d)) || (d > Int64.MaxValue) || (d < Int64.MinValue))
+					throw new CodeEE("\"" + st.Substring(stStartPos, stEndPos) + "\"は64ビット符号付整数の範囲を超えています");
+				significand = (Int64)d;
+			}
+			return significand;
+		}
+		//static Regex reg = new Regex(@"[0-9A-Fa-f]+", RegexOptions.Compiled);
+		private static Int64 readDigits(StringStream st, int fromBase)
+		{
+			int start = st.CurrentPosition;
+			//1756 正規表現を使ってみたがほぼ変わらなかったので没
+			//Match m = reg.Match(st.RowString, st.CurrentPosition);
+			//st.Jump(m.Length);
+			char c = st.Current;
+			if ((c == '-') || (c == '+'))
+			{
+				st.ShiftNext();
+			}
+			if (fromBase == 10)
+			{
+				while (!st.EOS)
+				{
+					c = st.Current;
+					if (char.IsDigit(c))
+					{
+						st.ShiftNext();
+						continue;
+					}
+					break;
+				}
+			}
+			else if (fromBase == 16)
+			{
+				while (!st.EOS)
+				{
+					c = st.Current;
+					if (char.IsDigit(c) || hexadecimalDigits.Contains(c))
+					{
+						st.ShiftNext();
+						continue;
+					}
+					break;
+				}
+			}
+			else if (fromBase == 2)
+			{
+				while (!st.EOS)
+				{
+					c = st.Current;
+					if (char.IsDigit(c))
+					{
+						if ((c != '0') && (c != '1'))
+							throw new CodeEE("二進法表記の中で使用できない文字が使われています");
+						st.ShiftNext();
+						continue;
+					}
+					break;
+				}
+			}
+			string strInt = st.Substring(start, st.CurrentPosition - start);
+			try
+			{
+				return Convert.ToInt64(strInt, fromBase);
+			}
+			catch (FormatException)
+			{
+				throw new CodeEE("\"" + strInt + "\"は整数値に変換できません");
+			}
+			catch (OverflowException)
+			{
+				throw new CodeEE("\"" + strInt + "\"は64ビット符号付き整数の範囲を超えています");
+			}
+			catch (ArgumentOutOfRangeException)
+			{
+				if (string.IsNullOrEmpty(strInt))
+					throw new CodeEE("数値として認識できる文字が必要です");
+				throw new CodeEE("文字列\"" + strInt + "\"は数値として認識できません");
+			}
+		}
+
+		/// <summary>
+		/// TIMES第二引数のみが使用する。
+		/// Convertクラスが発行する例外をそのまま投げるので適切に処理すること。
+		/// </summary>
+		/// <param name="st"></param>
+		/// <returns></returns>
+		public static double ReadDouble(StringStream st)
+		{
+			int start = st.CurrentPosition;
+			//大雑把に読み込んでエラー処理はConvertクラスに任せる。
+			//仮数小数部
+
+			if ((st.Current == '-') || (st.Current == '+'))
+			{
+				st.ShiftNext();
+			}
+			while (!st.EOS)
+			{//仮数部
+				char c = st.Current;
+                if (char.IsDigit(c) || (c == '.'))
+                {
+                    if ((c == '.') && (Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator == ","))
+                        st.Replace(st.CurrentPosition, 1, ",");
+
+                    st.ShiftNext();
+					continue;
+				}
+				break;
+			}
+			if ((st.Current == 'e') || (st.Current == 'E'))
+			{
+				st.ShiftNext();
+				if (st.Current == '-')
+				{
+					st.ShiftNext();
+				}
+				while (!st.EOS)
+				{//指数部
+					char c = st.Current;
+					if (char.IsDigit(c) || (c == '.'))
+					{
+						st.ShiftNext();
+						continue;
+					}
+					break;
+				}
+			}
+			return Convert.ToDouble(st.Substring(start, st.CurrentPosition - start));
+		}
+
+		/// <summary>
+		/// 行頭の単語の取得。マクロ展開あり。ただし単語でないマクロ展開はしない。
+		/// </summary>
+		/// <param name="st"></param>
+		/// <returns></returns>
+		public static IdentifierWord ReadFirstIdentifierWord(StringStream st)
+		{
+			int startpos = st.CurrentPosition;
+			string str = ReadSingleIdentifier(st);
+			if (string.IsNullOrEmpty(str))
+				throw new CodeEE("不正な文字で行が始まっています");
+			//1808a3 先頭1単語の展開をやめる。-命令の置換を禁止。
+			//if (UseMacro)
+			//{
+			//    int i = 0;
+			//    while (true)
+			//    {
+			//        DefineMacro macro = GlobalStatic.IdentifierDictionary.GetMacro(str);
+			//        i++;
+			//        if (i > MAX_EXPAND_MACRO)
+			//            throw new CodeEE("マクロの展開数が1文あたりの上限を超えました(自己参照・循環参照のおそれ)");
+			//        if (macro == null)
+			//            break;
+			//        //単語(識別子一個)でないマクロが出現したらここでは処理しない
+			//        if (macro.IDWord == null)
+			//        {
+			//            st.CurrentPosition = startpos;
+			//            return null;//変数処理に任せる。
+			//        }
+			//        str = macro.IDWord.Code;
+			//    }
+			//}
+			return new IdentifierWord(str);
+		}
+
+		/// <summary>
+		/// 単語の取得。マクロ展開あり。関数型マクロ展開なし
+		/// </summary>
+		/// <param name="st"></param>
+		/// <returns></returns>
+		public static IdentifierWord ReadSingleIdentifierWord(StringStream st)
+		{
+			string str = ReadSingleIdentifier(st);
+			if (string.IsNullOrEmpty(str))
+				return null;
+			if (UseMacro)
+			{
+				int i = 0;
+				while (true)
+				{
+					DefineMacro macro = GlobalStatic.IdentifierDictionary.GetMacro(str);
+					i++;
+					if (i > MAX_EXPAND_MACRO)
+						throw new CodeEE("マクロの展開数が1文あたりの上限値" + MAX_EXPAND_MACRO + "を超えました(自己参照・循環参照のおそれ)");
+					if (macro == null)
+						break;
+					if (macro.IDWord != null)
+						throw new CodeEE("マクロ" + macro.Keyword + "はこの文脈では使用できません(1単語に置き換えるマクロのみが使用できます)");
+					str = macro.IDWord.Code;
+				}
+			}
+			return new IdentifierWord(str);
+		}
+		
+		/// <summary>
+		/// 単語を文字列で取得。マクロ適用なし
+		/// </summary>
+		/// <param name="st"></param>
+		/// <returns></returns>
+		public static string ReadSingleIdentifier(StringStream st)
+		{
+			//1819 やや遅い。でもいずれやりたい
+			//Match m = idReg.Match(st.RowString, st.CurrentPosition);
+			//st.Jump(m.Length);
+			//return m.Value;
+			int start = st.CurrentPosition;
+			while (!st.EOS)
+			{
+				switch (st.Current)
+				{
+					case ' ':
+					case '\t':
+					case '+':
+					case '-':
+					case '*':
+					case '/':
+					case '%':
+					case '=':
+					case '!':
+					case '<':
+					case '>':
+					case '|':
+					case '&':
+					case '^':
+					case '~':
+					case '?':
+					case '#':
+					case ')':
+					case '}':
+					case ']':
+					case ',':
+					case ':':
+					case '(':
+					case '{':
+					case '[':
+					case '$':
+					case '\\':
+					case '\'':
+					case '\"':
+					case '@':
+					case '.':
+					case ';'://コメントに関しては直後に行われるであろうSkipWhiteSpaceなどが対応する。
+						goto end;
+					case ' ':
+						if (!Config.SystemAllowFullSpace)
+							throw new CodeEE("予期しない全角スペースを発見しました(この警告はシステムオプション「" + Config.GetConfigName(ConfigCode.SystemAllowFullSpace) + "」により無視できます)");
+						goto end;
+				}
+				st.ShiftNext();
+			}
+		end:
+			return st.Substring(start, st.CurrentPosition - start);
+		}
+
+		/// <summary>
+		/// endWithが見つかるまで読み込む。始点と終端のチェックは呼び出し側で行うこと。
+		/// エスケープあり。
+		/// </summary>
+		/// <param name="st"></param>
+		/// <returns></returns>
+		public static string ReadString(StringStream st, StrEndWith endWith)
+		{
+			StringBuilder buffer = new StringBuilder(100);
+			while (true)
+			{
+				switch (st.Current)
+				{
+					case '\0':
+						goto end;
+					case '\"':
+						if (endWith == StrEndWith.DoubleQuotation)
+							goto end;
+						break;
+					case '\'':
+						if (endWith == StrEndWith.SingleQuotation)
+							goto end;
+						break;
+					case ',':
+						if ((endWith == StrEndWith.Comma) || (endWith == StrEndWith.LeftParenthesis_Bracket_Comma_Semicolon))
+							goto end;
+						break;
+					case '(':
+					case '[':
+					case ';':
+						if (endWith == StrEndWith.LeftParenthesis_Bracket_Comma_Semicolon)
+							goto end;
+						break;
+					case '\\'://エスケープ処理
+						st.ShiftNext();//\を読み飛ばす
+						switch (st.Current)
+						{
+							case StringStream.EndOfString:
+								throw new CodeEE("エスケープ文字\\の後に文字がありません");
+							case '\n': break;
+							case 's': buffer.Append(' '); break;
+							case 'S': buffer.Append(' '); break;
+							case 't': buffer.Append('\t'); break;
+							case 'n': buffer.Append('\n'); break;
+							default: buffer.Append(st.Current); break;
+						}
+						st.ShiftNext();//\の次の文字を読み飛ばす
+						continue;
+				}
+				buffer.Append(st.Current);
+				st.ShiftNext();
+			}
+		end:
+			return buffer.ToString();
+		}
+
+		/// <summary>
+		/// 失敗したらCodeEE。OperatorManagerには頼らない
+		/// OperatorCode.Assignmentを返すことがある。
+		/// </summary>
+		/// <param name="st"></param>
+		/// <returns></returns>
+		public static OperatorCode ReadOperator(StringStream st, bool allowAssignment)
+		{
+			char cur = st.Current;
+			st.ShiftNext();
+			char next = st.Current;
+			switch (cur)
+			{
+				case '+':
+					if (next == '+')
+					{
+						st.ShiftNext();
+						return OperatorCode.Increment;
+					}
+					return OperatorCode.Plus;
+				case '-':
+					if (next == '-')
+					{
+						st.ShiftNext();
+						return OperatorCode.Decrement;
+					}
+					return OperatorCode.Minus;
+				case '*':
+					return OperatorCode.Mult;
+				case '/':
+					return OperatorCode.Div;
+				case '%':
+					return OperatorCode.Mod;
+				case '=':
+					if (next == '=')
+					{
+						st.ShiftNext();
+						return OperatorCode.Equal;
+					}
+					if (allowAssignment)
+						return OperatorCode.Assignment;
+					throw new CodeEE("予期しない代入演算子'='を発見しました(等価比較には'=='を使用してください)");
+				case '!':
+					if (next == '=')
+					{
+						st.ShiftNext();
+						return OperatorCode.NotEqual;
+					}
+					else if (next == '&')
+					{
+						st.ShiftNext();
+						return OperatorCode.Nand;
+					}
+					else if (next == '|')
+					{
+						st.ShiftNext();
+						return OperatorCode.Nor;
+					}
+					return OperatorCode.Not;
+				case '<':
+					if (next == '=')
+					{
+						st.ShiftNext();
+						return OperatorCode.LessEqual;
+					}
+					else if (next == '<')
+					{
+						st.ShiftNext();
+						return OperatorCode.LeftShift;
+					}
+					return OperatorCode.Less;
+				case '>':
+					if (next == '=')
+					{
+						st.ShiftNext();
+						return OperatorCode.GreaterEqual;
+					}
+					else if (next == '>')
+					{
+						st.ShiftNext();
+						return OperatorCode.RightShift;
+					}
+					return OperatorCode.Greater;
+				case '|':
+					if (next == '|')
+					{
+						st.ShiftNext();
+						return OperatorCode.Or;
+					}
+					return OperatorCode.BitOr;
+				case '&':
+					if (next == '&')
+					{
+						st.ShiftNext();
+						return OperatorCode.And;
+					}
+					return OperatorCode.BitAnd;
+				case '^':
+					if (next == '^')
+					{
+						st.ShiftNext();
+						return OperatorCode.Xor;
+					}
+					return OperatorCode.BitXor;
+				case '~':
+					return OperatorCode.BitNot;
+				case '?':
+					return OperatorCode.Ternary_a;
+				case '#':
+					return OperatorCode.Ternary_b;
+
+			}
+			throw new CodeEE("'" + cur + "'は演算子として認識できません");
+		}
+
+		/// <summary>
+		/// 失敗したらCodeEE。OperatorManagerには頼らない
+		/// "="の時、OperatorCode.Assignmentを返す。"=="の時はEqual
+		/// </summary>
+		/// <param name="st"></param>
+		/// <returns></returns>
+		public static OperatorCode ReadAssignmentOperator(StringStream st)
+		{
+			OperatorCode ret = OperatorCode.NULL;
+			char cur = st.Current;
+			st.ShiftNext();
+			char next = st.Current;
+			switch (cur)
+			{
+				case '+':
+					if (next == '+')
+						ret = OperatorCode.Increment;
+					else if (next == '=')
+						ret = OperatorCode.Plus;
+					break;
+				case '-':
+					if (next == '-')
+						ret = OperatorCode.Decrement;
+					else if (next == '=')
+						ret = OperatorCode.Minus;
+					break;
+				case '*':
+					if (next == '=')
+						ret = OperatorCode.Mult;
+					break;
+				case '/':
+					if (next == '=')
+						ret = OperatorCode.Div;
+					break;
+				case '%':
+					if (next == '=')
+						ret = OperatorCode.Mod;
+					break;
+				case '=':
+					if (next == '=')
+					{
+						ret = OperatorCode.Equal;
+						break;
+					}
+					return OperatorCode.Assignment;
+				case '\'':
+					if (next == '=')
+					{
+						ret = OperatorCode.AssignmentStr;
+						break;
+					}
+					throw new CodeEE("\"\'\"は代入演算子として認識できません");
+				case '<':
+					if (next == '<')
+					{
+						st.ShiftNext();
+						if (st.Current == '=')
+						{
+							ret = OperatorCode.LeftShift;
+							break;
+						}
+						throw new CodeEE("'<'は代入演算子として認識できません");
+					}
+					break;
+				case '>':
+					if (next == '>')
+					{
+						st.ShiftNext();
+						if (st.Current == '=')
+						{
+							ret = OperatorCode.RightShift;
+							break;
+						}
+						throw new CodeEE("'>'は代入演算子として認識できません");
+					}
+					break;
+				case '|':
+					if (next == '=')
+						ret = OperatorCode.BitOr;
+					break;
+				case '&':
+					if (next == '=')
+						ret = OperatorCode.BitAnd;
+					break;
+				case '^':
+					if (next == '=')
+						ret = OperatorCode.BitXor;
+					break;
+			}
+			if (ret == OperatorCode.NULL)
+				throw new CodeEE("'" + cur + "'は代入演算子として認識できません");
+			st.ShiftNext();
+			return ret;
+		}
+
+
+
+		/// <summary>
+		/// Consoleの文字表示用。字句解析や構文解析に使ってはならない
+		/// </summary>
+		public static int SkipAllSpace(StringStream st)
+		{
+			int count = 0;
+			while (true)
+			{
+				switch (st.Current)
+				{
+					case ' ':
+					case '\t':
+					case ' ':
+						count++;
+						st.ShiftNext();
+						continue;
+				}
+				return count;
+			}
+		}
+
+		public static bool IsWhiteSpace(char c)
+		{
+			return c == ' ' || c == '\t' || c == ' ';
+		}
+
+		/// <summary>
+		/// 字句解析・構文解析用。ホワイトスペースの他、コメントも飛ばす。
+		/// </summary>
+		public static int SkipWhiteSpace(StringStream st)
+		{
+			int count = 0;
+			while (true)
+			{
+				switch (st.Current)
+				{
+					case ' ':
+					case '\t':
+						count++;
+						st.ShiftNext();
+						continue;
+					case ' ':
+						if (!Config.SystemAllowFullSpace)
+							return count;
+						goto case ' ';
+					case ';':
+						if (st.CurrentEqualTo(";#;") && Program.DebugMode)
+						{
+							st.Jump(3);
+							continue;
+						}
+						else if (st.CurrentEqualTo(";!;"))
+						{
+							st.Jump(3);
+							continue;
+						}
+						st.Seek(0, SeekOrigin.End);
+						return count;
+				}
+				return count;
+			}
+		}
+
+		/// <summary>
+		/// 字句解析・構文解析用。文字列直前の半角スペースを飛ばす。性質上、半角スペースのみを見る。
+		/// </summary>
+		public static int SkipHalfSpace(StringStream st)
+		{
+			int count = 0;
+			while (st.Current == ' ')
+			{
+				count++;
+				st.ShiftNext();
+			}
+			return count;
+		}
+		#endregion
+
+		#region analyse
+		
+		/// <summary>
+		/// 解析できるものは関数宣言や式のみ。FORM文字列や普通の文字列を送ってはいけない
+		/// return時にはendWithの文字がCurrentになっているはず。終端の適切さの検証は呼び出し元が行う。
+		/// </summary>
+		/// <returns></returns>
+		public static WordCollection Analyse(StringStream st, LexEndWith endWith, LexAnalyzeFlag flag)
+		{
+			WordCollection ret = new WordCollection();
+			int nestBracketS = 0;
+			//int nestBracketM = 0;
+			int nestBracketL = 0;
+			while (true)
+			{
+				switch (st.Current)
+				{
+					case '\n':
+					case '\0':
+						goto end;
+					case ' ':
+					case '\t':
+						st.ShiftNext();
+						continue;
+					case ' ':
+						if (!Config.SystemAllowFullSpace)
+							throw new CodeEE("字句解析中に予期しない全角スペースを発見しました(この警告はシステムオプション「" + Config.GetConfigName(ConfigCode.SystemAllowFullSpace) + "」により無視できます)");
+						st.ShiftNext();
+						continue;
+					case '0':
+					case '1':
+					case '2':
+					case '3':
+					case '4':
+					case '5':
+					case '6':
+					case '7':
+					case '8':
+					case '9':
+						ret.Add(new LiteralIntegerWord(ReadInt64(st, false)));
+						break;
+					case '>':
+						if(endWith == LexEndWith.GreaterThan)
+							goto end;
+						goto case '+';
+					case '+':
+					case '-':
+					case '*':
+					case '/':
+					case '%':
+					case '=':
+					case '!':
+					case '<':
+					case '|':
+					case '&':
+					case '^':
+					case '~':
+					case '?':
+					case '#':
+						if ((nestBracketS == 0) && (nestBracketL == 0))
+						{
+							if (endWith == LexEndWith.Operator)
+								goto end;//代入演算子のはずである。呼び出し元がチェックするはず
+							if ((endWith == LexEndWith.Percent) && (st.Current == '%'))
+								goto end;
+							if ((endWith == LexEndWith.Question) && (st.Current == '?'))
+								goto end;
+						}
+						ret.Add(new OperatorWord(ReadOperator(st, (flag & LexAnalyzeFlag.AllowAssignment) == LexAnalyzeFlag.AllowAssignment)));
+						break;
+					case ')': ret.Add(new SymbolWord(')')); nestBracketS--; st.ShiftNext(); continue;
+					case ']': ret.Add(new SymbolWord(']')); nestBracketL--; st.ShiftNext(); continue;
+					case '(': ret.Add(new SymbolWord('(')); nestBracketS++; st.ShiftNext(); continue;
+					case '[':
+						if (st.Next == '[')
+						{
+							//throw new CodeEE("字句解析中に予期しない文字'[['を発見しました");
+							////1808alpha006 rename処理変更
+							//1808beta009 ここだけ戻す
+							//現在の処理だとここに来た時点でrename失敗確定だが警告内容を元に戻すため
+							if (ParserMediator.RenameDic == null)
+								throw new CodeEE("字句解析中に予期しない文字\"[[\"を発見しました");
+							int start = st.CurrentPosition;
+							int find = st.Find("]]");
+							if (find <= 2)
+							{
+								if (find == 2)
+									throw new CodeEE("空の[[]]です");
+								throw new CodeEE("対応する\"]]\"のない\"[[\"です");
+							}
+							string key = st.Substring(start, find + 2);
+							//1810 ここまでで置換できなかったものは強制エラーにする
+							//行連結前に置換不能で行連結より置換することができるようになったものまで置換されていたため
+							throw new CodeEE("字句解析中に置換(rename)できない符号" + key + "を発見しました");
+							//string value = null;
+							//if (!ParserMediator.RenameDic.TryGetValue(key, out value))
+							//    throw new CodeEE("字句解析中に置換(rename)できない符号" + key + "を発見しました");
+							//st.Replace(start, find + 2, value);
+							//continue;//その場から再度解析スタート
+						}
+						ret.Add(new SymbolWord('[')); nestBracketL++; st.ShiftNext(); continue;
+					case ':': ret.Add(new SymbolWord(':')); st.ShiftNext(); continue;
+					case ',':
+						if ((endWith == LexEndWith.Comma) && (nestBracketS == 0))// && (nestBracketL == 0))
+							goto end;
+						ret.Add(new SymbolWord(',')); st.ShiftNext(); continue;
+					//case '}': ret.Add(new SymbolWT('}')); nestBracketM--; continue;
+					//case '{': ret.Add(new SymbolWT('{')); nestBracketM++; continue;
+					case '\'':
+						if ((flag & LexAnalyzeFlag.AllowSingleQuotationStr) == LexAnalyzeFlag.AllowSingleQuotationStr)
+						{
+							st.ShiftNext();
+							ret.Add(new LiteralStringWord(ReadString(st, StrEndWith.SingleQuotation)));
+							if (st.Current != '\'')
+								throw new CodeEE("\'が閉じられていません");
+							st.ShiftNext();
+							break;
+						}
+						if ((flag & LexAnalyzeFlag.AnalyzePrintV) != LexAnalyzeFlag.AnalyzePrintV)
+						{
+							//AssignmentStr用特殊処理 代入文の代入演算子を探索中で'=の場合のみ許可
+							if ((endWith == LexEndWith.Operator) && (nestBracketS == 0) && (nestBracketL == 0) && st.Next == '=' )
+								goto end;
+							throw new CodeEE("字句解析中に予期しない文字'" + st.Current + "'を発見しました");
+						}
+						st.ShiftNext();
+						ret.Add(new LiteralStringWord(ReadString(st, StrEndWith.Comma)));
+						if (st.Current == ',')
+							goto case ',';//続きがあるなら,の処理へ。それ以外は行終端のはず
+						goto end;
+					case '}':
+						if (endWith == LexEndWith.RightCurlyBrace)
+							goto end;
+						throw new CodeEE("字句解析中に予期しない文字'" + st.Current + "'を発見しました");
+					case '\"':
+						st.ShiftNext();
+						ret.Add(new LiteralStringWord(ReadString(st, StrEndWith.DoubleQuotation)));
+						if (st.Current != '\"')
+							throw new CodeEE("\"が閉じられていません");
+						st.ShiftNext();
+						break;
+					case '@':
+						if (st.Next != '\"')
+						{
+							ret.Add(new SymbolWord('@'));
+							st.ShiftNext();
+							continue;
+						}
+						st.ShiftNext();
+						st.ShiftNext();
+						ret.Add(AnalyseFormattedString(st, FormStrEndWith.DoubleQuotation, false));
+						if (st.Current != '\"')
+							throw new CodeEE("\"が閉じられていません");
+						st.ShiftNext();
+						break;
+					case '.':
+						ret.Add(new SymbolWord('.'));
+						st.ShiftNext();
+						continue;
+
+					case '\\':
+						if (st.Next != '@')
+							throw new CodeEE("字句解析中に予期しない文字'" + st.Current + "'を発見しました");
+						{
+							st.Jump(2);
+							ret.Add(new StrFormWord(new[] { "", "" }, new SubWord[] { AnalyseYenAt(st) }));
+						}
+						break;
+					case '{':
+					case '$':
+						throw new CodeEE("字句解析中に予期しない文字'" + st.Current + "'を発見しました");
+					case ';'://1807 行中コメント
+						if (st.CurrentEqualTo(";#;") && Program.DebugMode)
+						{
+							st.Jump(3);
+							break;
+						}
+						else if (st.CurrentEqualTo(";!;"))
+						{
+							st.Jump(3);
+							break;
+						}
+						st.Seek(0, SeekOrigin.End);
+						goto end;
+					default:
+						{
+							ret.Add(new IdentifierWord(ReadSingleIdentifier(st)));
+							break;
+						}
+				}
+			}
+		end:
+			if ((nestBracketS != 0) || (nestBracketL != 0))
+			{
+				if (nestBracketS < 0)
+					throw new CodeEE("字句解析中に対応する'('のない')'を発見しました");
+				if (nestBracketS > 0)
+					throw new CodeEE("字句解析中に対応する')'のない'('を発見しました");
+				if (nestBracketL < 0)
+					throw new CodeEE("字句解析中に対応する'['のない']'を発見しました");
+				if (nestBracketL > 0)
+					throw new CodeEE("字句解析中に対応する']'のない'['を発見しました");
+			}
+			if (UseMacro)
+				return expandMacro(ret);
+			return ret;
+
+		}
+
+		private static WordCollection expandMacro(WordCollection wc)
+		{
+			//マクロ展開
+			wc.Pointer = 0;
+			int count = 0;
+			while (!wc.EOL)
+			{
+				IdentifierWord word = wc.Current as IdentifierWord;
+				if (word == null)
+				{
+					wc.ShiftNext();
+					continue;
+				}
+				string idStr = word.Code;
+				DefineMacro macro = GlobalStatic.IdentifierDictionary.GetMacro(idStr);
+				if (macro == null)
+				{
+					wc.ShiftNext();
+					continue;
+				}
+				count++;
+				if (count > MAX_EXPAND_MACRO)
+					throw new CodeEE("マクロの展開数が1文あたりの上限" + MAX_EXPAND_MACRO + "を超えました(自己参照・循環参照のおそれ)");
+				if (!macro.HasArguments)
+				{
+					wc.Remove();
+					wc.InsertRange(macro.Statement);
+					continue;
+				}
+				//関数型マクロ
+				wc = expandFunctionlikeMacro(macro, wc);
+			}
+			wc.Pointer = 0;
+			return wc;
+		}
+
+		private static WordCollection expandFunctionlikeMacro(DefineMacro macro, WordCollection wc)
+		{
+			int macroStart = wc.Pointer;
+			wc.ShiftNext();
+			SymbolWord symbol = wc.Current as SymbolWord;
+			if (symbol == null || symbol.Type != '(')
+				throw new CodeEE("関数形式のマクロ" + macro.Keyword + "に引数がありません");
+			WordCollection macroWC = macro.Statement.Clone();
+			WordCollection[] args = new WordCollection[macro.ArgCount];
+			//引数部読み取りループ
+			for (int i = 0; i < macro.ArgCount; i++)
+			{
+				int macroNestBracketS = 0;
+				args[i] = new WordCollection();
+				while (true)
+				{
+					wc.ShiftNext();
+					if (wc.EOL)
+						throw new CodeEE("関数形式のマクロ" + macro.Keyword + "の用法が正しくありません");
+					symbol = wc.Current as SymbolWord;
+					if (symbol == null)
+					{
+						args[i].Add(wc.Current);
+						continue;
+					}
+					switch (symbol.Type)
+					{
+						case '(': macroNestBracketS++; break;
+						case ')':
+							if (macroNestBracketS > 0)
+							{
+								macroNestBracketS--;
+								break;
+							}
+							if (i != macro.ArgCount - 1)
+								throw new CodeEE("関数形式のマクロ" + macro.Keyword + "の引数の数が正しくありません");
+							goto exitfor;
+						case ',':
+							if (macroNestBracketS == 0)
+								goto exitwhile;
+							break;
+					}
+					args[i].Add(wc.Current);
+				}
+			exitwhile:
+				if (args[i].Collection.Count == 0)
+					throw new CodeEE("関数形式のマクロ" + macro.Keyword + "の引数を省略することはできません");
+			}
+		//引数部読み取りループ終端
+		exitfor:
+			symbol = wc.Current as SymbolWord;
+			if (symbol == null || symbol.Type != ')')
+				throw new CodeEE("関数形式のマクロ" + macro.Keyword + "の用法が正しくありません");
+			int macroLength = wc.Pointer - macroStart + 1;
+			wc.Pointer = macroStart;
+			for (int j = 0; j < macroLength; j++)
+				wc.Collection.RemoveAt(macroStart);
+			while (!macroWC.EOL)
+			{
+				MacroWord w = macroWC.Current as MacroWord;
+				if (w == null)
+				{
+					macroWC.ShiftNext();
+					continue;
+				}
+				macroWC.Remove();
+				macroWC.InsertRange(args[w.Number]);
+				macroWC.Pointer += args[w.Number].Collection.Count;
+			}
+			wc.InsertRange(macroWC);
+			wc.Pointer = macroStart;
+			return wc;
+		}
+
+		/// <summary>
+		/// @"などの直後からの開始
+		/// return時にはendWithの文字がCurrentになっているはず。終端の適切さの検証は呼び出し元が行う。
+		/// </summary>
+		/// <returns></returns>
+		public static StrFormWord AnalyseFormattedString(StringStream st, FormStrEndWith endWith, bool trim)
+		{
+			List<string> strs = new List<string>();
+			List<SubWord> SWTs = new List<SubWord>();
+			StringBuilder buffer = new StringBuilder(100);
+			while (true)
+			{
+				char cur = st.Current;
+				switch (cur)
+				{
+					case '\n':
+					case '\0':
+						goto end;
+					case '\"':
+						if (endWith == FormStrEndWith.DoubleQuotation)
+							goto end;
+						buffer.Append(cur);
+						break;
+					case '#':
+						if (endWith == FormStrEndWith.Sharp)
+							goto end;
+						buffer.Append(cur);
+						break;
+					case ',':
+						if ((endWith == FormStrEndWith.Comma) || (endWith == FormStrEndWith.LeftParenthesis_Bracket_Comma_Semicolon))
+							goto end;
+						buffer.Append(cur);
+						break;
+					case '(':
+					case '[':
+					case ';':
+						if (endWith == FormStrEndWith.LeftParenthesis_Bracket_Comma_Semicolon)
+							goto end;
+						buffer.Append(cur);
+						break;
+					case '%':
+						strs.Add(buffer.ToString());
+						buffer.Remove(0, buffer.Length);
+						st.ShiftNext();
+						SWTs.Add(new PercentSubWord(Analyse(st, LexEndWith.Percent, LexAnalyzeFlag.None)));
+						if (st.Current != '%')
+							throw new CodeEE("\'%\'が使われましたが対応する\'%\'が見つかりません");
+						break;
+					case '{':
+						strs.Add(buffer.ToString());
+						buffer.Remove(0, buffer.Length);
+						st.ShiftNext();
+						SWTs.Add(new CurlyBraceSubWord(Analyse(st, LexEndWith.RightCurlyBrace, LexAnalyzeFlag.None)));
+						if (st.Current != '}')
+							throw new CodeEE("\'{\'が使われましたが対応する\'}\'が見つかりません");
+						break;
+					case '*':
+					case '+':
+					case '=':
+					case '/':
+					case '$':
+						if (!Config.SystemIgnoreTripleSymbol && st.TripleSymbol())
+						{
+							strs.Add(buffer.ToString());
+							buffer.Remove(0, buffer.Length);
+							st.Jump(3);
+							SWTs.Add(new TripleSymbolSubWord(cur));
+							continue;
+						}
+						else
+							buffer.Append(cur);
+						break;
+					case '\\'://エスケープ文字の使用
+
+						st.ShiftNext();
+						cur = st.Current;
+						switch (cur)
+						{
+							case '\0':
+								throw new CodeEE("エスケープ文字\\の後に文字がありません");
+							case '\n': break;
+							case 's': buffer.Append(' '); break;
+							case 'S': buffer.Append(' '); break;
+							case 't': buffer.Append('\t'); break;
+							case 'n': buffer.Append('\n'); break;
+							case '@'://\@~~?~~#~~\@
+								{
+									if ((endWith == FormStrEndWith.YenAt) || (endWith == FormStrEndWith.Sharp))
+										goto end;
+									strs.Add(buffer.ToString());
+									buffer.Remove(0, buffer.Length);
+									st.ShiftNext();
+									SWTs.Add(AnalyseYenAt(st));
+									continue;
+								}
+							default:
+								buffer.Append(cur);
+								st.ShiftNext();
+								continue;
+						}
+						break;
+					default:
+						buffer.Append(cur);
+						break;
+				}
+				st.ShiftNext();
+			}
+		end:
+			strs.Add(buffer.ToString());
+
+			string[] retStr = new string[strs.Count];
+			SubWord[] retSWTs = new SubWord[SWTs.Count];
+			strs.CopyTo(retStr);
+			SWTs.CopyTo(retSWTs);
+			if (trim && retStr.Length > 0)
+			{
+				retStr[0] = retStr[0].TrimStart(' ', '\t');
+				retStr[retStr.Length - 1] = retStr[retStr.Length - 1].TrimEnd(' ', '\t');
+			}
+			return new StrFormWord(retStr, retSWTs);
+		}
+
+
+
+		/// <summary>
+		/// \@直後からの開始、\@の直後がCurrentになる
+		/// </summary>
+		/// <param name="st"></param>
+		/// <returns></returns>
+		public static YenAtSubWord AnalyseYenAt(StringStream st)
+		{
+			WordCollection w = Analyse(st, LexEndWith.Question, LexAnalyzeFlag.None);
+			if (st.Current != '?')
+				throw new CodeEE("\'\\@\'が使われましたが対応する\'?\'が見つかりません");
+			st.ShiftNext();
+			StrFormWord left = AnalyseFormattedString(st, FormStrEndWith.Sharp, true);
+			if (st.Current != '#')
+			{
+				if (st.Current != '@')
+					throw new CodeEE("\'\\@\',\'?\'が使われましたが対応する\'#\'が見つかりません");
+				st.ShiftNext();
+				ParserMediator.Warn("\'\\@\',\'?\'が使われましたが対応する\'#\'が見つかりません", GlobalStatic.Process.GetScaningLine(), 1, false, false);
+				return new YenAtSubWord(w, left, null);
+			}
+			st.ShiftNext();
+			StrFormWord right = AnalyseFormattedString(st, FormStrEndWith.YenAt, true);
+			if (st.Current != '@')
+				throw new CodeEE("\'\\@\',\'?\',\'#\'が使われましたが対応する\'\\@\'が見つかりません");
+			st.ShiftNext();
+			return new YenAtSubWord(w, left, right);
+		}
+
+		#endregion
+
+	}
+}

+ 156 - 0
NTERA/Game/Sub/StringStream.cs

@@ -0,0 +1,156 @@
+using System;
+using System.IO;
+
+namespace MinorShift.Emuera.Sub
+{
+	/// <summary>
+	/// 文字列を1文字ずつ評価するためのクラス
+	/// </summary>
+	internal sealed class StringStream
+	{
+		public StringStream(string s)
+		{
+			source = s ?? "";
+		    CurrentPosition = 0;
+		}
+
+		string source;
+		public const char EndOfString = '\0';
+	    public string RowString => source;
+
+	    public int CurrentPosition { get; set; }
+
+	    public char Current
+		{
+			get
+			{
+				if (CurrentPosition >= source.Length)
+					return EndOfString;
+				return source[CurrentPosition];
+			}
+		}
+		
+		public void AppendString(string str)
+		{
+			if (CurrentPosition > source.Length)
+				CurrentPosition = source.Length;
+			source += " " + str;
+		}
+		
+		/// <summary>
+		/// 文字列終端に達した
+		/// </summary>
+		public bool EOS => CurrentPosition >= source.Length;
+
+		///変数の区切りである"[["と"]]"の先読みなどに使用
+		public char Next
+		{
+			get
+			{
+				if (CurrentPosition + 1 >= source.Length)
+					return EndOfString;
+				return source[CurrentPosition + 1];
+			}
+		}
+
+		public string Substring()
+		{
+			if (CurrentPosition >= source.Length)
+				return "";
+			if (CurrentPosition == 0)
+				return source;
+			return source.Substring(CurrentPosition);
+		}
+
+		public string Substring(int start, int length)
+		{
+			if (start >= source.Length || length == 0)
+				return "";
+			if (start + length > source.Length)
+				length = source.Length - start;
+			return source.Substring(start, length);
+		}
+
+		internal void Replace(int start, int count, string src)
+		{
+			//引数に正しい数字が送られてくること前提
+			source = (source.Remove(start, count)).Insert(start, src);
+			CurrentPosition = start;
+		}
+
+		public void ShiftNext()
+		{
+			CurrentPosition++;
+		}
+
+        public void Jump(int skip)
+        {
+            CurrentPosition += skip;
+        }
+
+		/// <summary>
+		/// 検索文字列の相対位置を返す。見つからない場合、負の値。
+		/// </summary>
+		/// <param name="str"></param>
+		public int Find(string str)
+		{
+			return source.IndexOf(str, CurrentPosition) - CurrentPosition;
+		}
+
+		/// <summary>
+		/// 検索文字列の相対位置を返す。見つからない場合、負の値。
+		/// </summary>
+		public int Find(char c)
+		{
+			return source.IndexOf(c, CurrentPosition) - CurrentPosition;
+		}
+
+		public override string ToString()
+		{
+			if (source == null)
+				return "";
+			return source;
+		}
+
+		public bool CurrentEqualTo(string rother)
+		{
+			if (CurrentPosition + rother.Length > source.Length)
+				return false;
+
+			for (int i = 0;  i < rother.Length;i++)
+			{
+				if (source[CurrentPosition + i] != rother[i])
+					return false;
+			}
+			return true;
+		}
+
+		public bool TripleSymbol()
+		{
+			if (CurrentPosition + 3 > source.Length)
+				return false;
+			return (source[CurrentPosition] == source[CurrentPosition + 1]) && (source[CurrentPosition] == source[CurrentPosition + 2]);
+		}
+
+
+		public bool CurrentEqualTo(string rother, StringComparison comp)
+		{
+			if (CurrentPosition + rother.Length > source.Length)
+				return false;
+			string sub = source.Substring(CurrentPosition, rother.Length);
+			return sub.Equals(rother, comp);
+		}
+
+		public void Seek(int offset, SeekOrigin origin)
+		{
+			if (origin == SeekOrigin.Begin)
+				CurrentPosition = offset;
+			else if (origin == SeekOrigin.Current)
+				CurrentPosition = CurrentPosition + offset;
+			else if (origin == SeekOrigin.End)
+				CurrentPosition = source.Length + offset;
+			if (CurrentPosition < 0)
+				CurrentPosition = 0;
+		}
+	}
+}

+ 58 - 0
NTERA/Game/Sub/SubWord.cs

@@ -0,0 +1,58 @@
+namespace MinorShift.Emuera.Sub
+{
+	/// <summary>
+	/// FormattedStringWTの中身用のトークン
+	/// </summary>
+	internal abstract class SubWord
+	{
+		protected SubWord(WordCollection w) { words = w; }
+		readonly WordCollection words;
+		public WordCollection Words => words;
+		public bool IsMacro;
+		public virtual void SetIsMacro()
+		{
+			IsMacro = true;
+			if(Words != null)
+				Words.SetIsMacro();
+			
+		}
+	}
+
+	internal sealed class TripleSymbolSubWord : SubWord
+	{
+		public TripleSymbolSubWord(char c) : base(null) { code = c; }
+		readonly char code;
+		public char Code => code;
+	}
+	internal sealed class CurlyBraceSubWord : SubWord
+	{
+		public CurlyBraceSubWord(WordCollection w) : base(w) { }
+	}
+
+	internal sealed class PercentSubWord : SubWord
+	{
+		public PercentSubWord(WordCollection w) : base(w) { }
+	}
+
+	internal sealed class YenAtSubWord : SubWord
+	{
+		public YenAtSubWord(WordCollection w, StrFormWord fsLeft, StrFormWord fsRight)
+			: base(w)
+		{
+			left = fsLeft;
+			right = fsRight;
+		}
+		readonly StrFormWord left;
+		readonly StrFormWord right;
+		public StrFormWord Left => left;
+		public StrFormWord Right => right;
+
+		public override void SetIsMacro()
+		{
+			IsMacro = true;
+			Words.SetIsMacro();
+			Left.SetIsMacro();
+			Right.SetIsMacro();
+		}
+	}
+}

+ 138 - 0
NTERA/Game/Sub/Word.cs

@@ -0,0 +1,138 @@
+using System;
+using MinorShift.Emuera.GameData.Expression;
+
+namespace MinorShift.Emuera.Sub
+{
+	internal abstract class Word
+	{
+		public abstract char Type { get; }
+		public bool IsMacro;
+		public virtual void SetIsMacro()
+		{
+			IsMacro = true;
+		}
+	}
+
+	internal sealed class NullWord : Word
+	{
+		public override char Type => '\0';
+
+		public override string ToString()
+		{
+			return "/null/";
+		}
+	}
+
+	internal sealed class IdentifierWord : Word
+	{
+		public IdentifierWord(string s) { code = s; }
+		readonly string code;
+		public string Code => code;
+		public override char Type => 'A';
+
+		public override string ToString()
+		{
+			return code;
+		}
+	}
+
+	internal sealed class LiteralIntegerWord : Word
+	{
+		public LiteralIntegerWord(Int64 i) { code = i; }
+		readonly Int64 code;
+		public Int64 Int => code;
+		public override char Type => '0';
+
+		public override string ToString()
+		{
+			return code.ToString();
+		}
+	}
+
+	internal sealed class LiteralStringWord : Word
+	{
+		public LiteralStringWord(string s) { code = s; }
+		readonly string code;
+		public string Str => code;
+		public override char Type => '\"';
+
+		public override string ToString()
+		{
+			return "\"" + code + "\"";
+		}
+	}
+
+
+	internal sealed class OperatorWord : Word
+	{
+		public OperatorWord(OperatorCode op) { code = op; }
+		readonly OperatorCode code;
+		public OperatorCode Code => code;
+		public override char Type => '=';
+
+		public override string ToString()
+		{
+			return code.ToString();
+		}
+	}
+
+	internal sealed class SymbolWord : Word
+	{
+		public SymbolWord(char c) { code = c; }
+		readonly char code;
+		public override char Type => code;
+
+		public override string ToString()
+		{
+			return code.ToString();
+		}
+	}
+
+	internal sealed class StrFormWord : Word
+	{
+
+		public StrFormWord(string[] s, SubWord[] SWT) { strs = s; subwords = SWT; }
+		readonly string[] strs;
+		readonly SubWord[] subwords;
+		public string[] Strs => strs;
+		public SubWord[] SubWords => subwords;
+		public override char Type //@はSymbolがつかっちゃった
+			=> 'F';
+
+		public override void SetIsMacro()
+		{
+			IsMacro = true;
+			foreach(SubWord subword in SubWords)
+			{
+				subword.SetIsMacro();
+			}
+		}
+	}
+
+
+	internal sealed class TermWord : Word
+	{
+		public TermWord(IOperandTerm term) { this.term = term; }
+		readonly IOperandTerm term;
+		public IOperandTerm Term => term;
+		public override char Type => 'T';
+	}
+	
+	internal sealed class MacroWord : Word
+	{
+		public MacroWord(int num) { this.num = num; }
+		readonly int num;
+		public int Number => num;
+		public override char Type => 'M';
+
+		public override string ToString()
+		{
+			return "Arg" + num;
+		}
+	}
+	
+	
+	
+	
+	
+}

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä