Skip to content

Instantly share code, notes, and snippets.

@EbiseLutica
Last active August 29, 2015 14:07
Show Gist options
  • Save EbiseLutica/e1e4563843aa23e99859 to your computer and use it in GitHub Desktop.
Save EbiseLutica/e1e4563843aa23e99859 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Calc
{
class PolaScript
{
static string[] token;
static int ix;
static Dictionary<string, Constant> varlist = new Dictionary<string, Constant>();
//3 + 2
static void Main(string[] args)
{
while (true)
{
string dat = Console.ReadLine();
//Console.WriteLine(ArrayToString(GetTokenByExpression(dat)));
try
{
string[] hoge = GetTokenByExpression(dat);
Console.WriteLine("Tokens: {0}", string.Join(", ", hoge));
Expression(hoge);
ConstExpression(hoge);
}
catch (Exception ex)
{
System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(ex, true);
Console.Error.WriteLine("[ERROR!!!: {0}]{1}\r\nStackTrace: \r\n", ex.GetType().Name, ex.Message);
foreach (var frame in trace.GetFrames())
{
Console.Error.WriteLine("{0}, {1} : {2}", frame.GetFileLineNumber(), frame.GetFileColumnNumber(), frame.GetMethod());
}
}
}
}
static string ArrayToString(object[] array)
{
string lastdata = "";
foreach (object val in array)
{
lastdata += val.ToString() + " ";
}
return lastdata;
}
static string[] GetTokenByExpression(string source)
{
TokenMode tm = TokenMode.Null;
string tmp = "";
List<string> lastdata = new List<string>();
bool isString = false;
int c = 0;
foreach (char chr in source)
{
if (!isString)
{
if (char.IsSeparator(chr))
{
if (tmp != "")
{
lastdata.Add(tmp);
tmp = "";
}
continue;
}
TokenMode nowtm = TokenMode.Null;
if (char.IsNumber(chr) || chr == '.' || chr == '\\')
nowtm = TokenMode.Value;
else if (
chr == '+' || chr == '-'
|| chr == '*' || chr == '/' || chr == '%'
|| chr == '(' || chr == ')'
|| chr == '<' || chr == '>' || chr == '='
|| chr == '&' || chr == '|' || chr == '^'
|| chr == '!' || chr == '~'
)
{
nowtm = TokenMode.Operation;
}
if ((nowtm != tm || (nowtm == TokenMode.Operation && tm == TokenMode.Operation)))
{
tm = nowtm;
if (tmp != "" && tmp + chr != "<=" && tmp + chr != ">=" && tmp + chr != "==" && tmp + chr != "!=" && tmp + chr != "<<" && tmp + chr != ">>"
&& tmp + chr != "+=" && tmp + chr != "-=" && tmp + chr != "*=" && tmp + chr != "/=" && tmp + chr != "&=" && tmp + chr != "|=" && tmp + chr != "^=")
{
lastdata.Add(tmp);
tmp = "";
}
}
}
if (c > 0)
{
if (chr == '"' && (tmp + chr).Substring(tmp.Length - 2) != "\\\"")
isString = !isString;
}
else
if (chr == '"')
isString = !isString;
tmp += chr;
}
if (tmp != "")
{
lastdata.Add(tmp);
}
return lastdata.ToArray();
}
public enum TokenMode
{
Null, Value, Operation
}
static Node CreateNode(string name)
{
Node pnode = new Node();
pnode.childs = new List<Node>();
pnode.name = name;
return pnode;
}
static void AddChild(ref Node pnode, Node pchild)
{
//if (pnode.name == "=" || pnode.name == "+=" || pnode.name == "-=" || pnode.name == "*=" || pnode.name == "/=" || pnode.name == "&=" || pnode.name == "|=" || pnode.name == "^=")
// pnode.childs.Insert(0, pchild);
//else
pnode.childs.Add(pchild);
}
static void AddTwoChildren(ref Node pnode, Node pchild1, Node pchild2)
{
AddChild(ref pnode, pchild1);
AddChild(ref pnode, pchild2);
}
static Node SetAssignment()
{
Node pleft = SetVariableDeclaration();
while (ix < token.Length && (token[ix] == "=" || token[ix] == "+=" || token[ix] == "-=" || token[ix] == "*=" || token[ix] == "/=" || token[ix] == "&=" || token[ix] == "|=" || token[ix] == "^="))
{
Node pnode = CreateNode(token[ix++]);
Node pright = SetAssignment();
AddTwoChildren(ref pnode, pleft, pright);
pleft = pnode;
}
return pleft;
}
static Node SetVariableDeclaration()
{
Node pright = SetLogic();
while (ix < token.Length && (token[ix] == "num" || token[ix] == "string" || token[ix] == "bool" || token[ix] == "Number" || token[ix] == "String" || token[ix] == "Boolean"))
{
Node pleft = CreateNode(token[ix++]);
Node pnode = CreateNode("let");
AddTwoChildren(ref pnode, pleft, pright);
pright = pnode;
}
return pright;
}
//3 + 2 - 5
//( - ( + 3 2) 5 )
//a = b = c
//( = a ( = b c) )
static Node SetLogic()
{
Node pleft = SetBit();
while (ix < token.Length && (token[ix] == "<" || token[ix] == ">" || token[ix] == "==" || token[ix] == "!=" || token[ix] == "<=" || token[ix] == ">="))
{
Node pnode = CreateNode(token[ix++]);
Node pright = SetShift();
AddTwoChildren(ref pnode, pleft, pright);
pleft = pnode;
}
return pleft;
}
static Node SetBit()
{
Node pleft = SetShift();
while (ix < token.Length && (token[ix] == "&" || token[ix] == "|" || token[ix] == "^"))
{
Node pnode = CreateNode(token[ix++]);
Node pright = SetLogic();
AddTwoChildren(ref pnode, pleft, pright);
pleft = pnode;
}
return pleft;
}
static Node SetShift()
{
Node pleft = SetAddSub();
while (ix < token.Length && (token[ix] == "<<" || token[ix] == ">>"))
{
Node pnode = CreateNode(token[ix++]);
Node pright = SetAddSub();
AddTwoChildren(ref pnode, pleft, pright);
pleft = pnode;
}
return pleft;
}
static Node SetAddSub()
{
Node pleft = SetMulDiv();
while(ix < token.Length && (token[ix] == "+" || token[ix] == "-"))
{
Node pnode = CreateNode(token[ix++]);
Node pright = SetMulDiv();
AddTwoChildren(ref pnode, pleft, pright);
pleft = pnode;
}
return pleft;
}
static Node SetMulDiv()
{
Node pleft = SetFactor();
while (ix < token.Length && (token[ix] == "*" || token[ix] == "/" || token[ix] == "%"))
{
Node pnode = CreateNode(token[ix++]);
Node pright = SetFactor();
AddTwoChildren(ref pnode, pleft, pright);
pleft = pnode;
}
return pleft;
}
static Node SetFactor()
{
Node pnode;
if (token[ix] == "(")
{
ix++;
pnode = SetBit();
if (token[ix++] != ")")
throw new Exception("\")\"がありません。");
}
else if (token[ix] == "-" || token[ix] == "~" || token[ix] == "!")
{
pnode = CreateNode(token[ix++]);
Node pright = SetAssignment();
AddChild(ref pnode, pright);
}
else
{
string tmp = token[ix++];
if (isNumber(tmp)) //数値
{
pnode = CreateNode("num");
pnode.value = tmp;
}
else if (isVarName(tmp))
{
pnode = CreateNode("var");
pnode.value = tmp;
}
else if (tmp[0] == '"' && tmp[tmp.Length - 1] == '"' && tmp.Length > 1)
{
pnode = CreateNode("str");
pnode.value = tmp.Substring(1, tmp.Length - 2);
}
else if (tmp == "true" || tmp == "false")
{
pnode = CreateNode("bool");
pnode.value = tmp;
}
else
{
throw new Exception(tmp + " を理解できません。");
}
}
return pnode;
}
static bool isNumber(string val)
{
double d;
return double.TryParse(val, out d);
}
static bool isVarName(string val)
{
bool lastdata = true;
int cnt = 0;
foreach (char c in val)
{
if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (cnt > 0 && c >= '0' && c <= '9') || (c == '_')))
{
lastdata = false;
}
cnt++;
}
return lastdata;
}
static string GetAST(Node node)
{
StringBuilder lastdata = new StringBuilder();
lastdata.AppendFormat(" ({0}", node.name);
for (int n = 0; n < node.childs.Count; n++)
{
Node pchild = node.childs[n];
if (pchild.name == "num" || pchild.name == "bool" || pchild.name == "var")
lastdata.AppendFormat(" {0} {1}", pchild.name, pchild.value);
else if (pchild.name == "str")
lastdata.AppendFormat(" {0} \"{1}\"", pchild.name, pchild.value);
else
lastdata.Append(GetAST(pchild));
}
lastdata.Append(")");
return lastdata.ToString();
}
static void Expression(string[] intoken)
{
foreach (string data in intoken)
Console.Write(data + " ");
Console.Write(" => ");
token = intoken;
ix = 0;
Node expr = SetAssignment();
Console.Write(GetAST(expr));
Console.WriteLine();
}
static Constant Calc(Node pnode)
{
if (pnode.name == "num")
return new Constant(Types.Number, double.Parse(pnode.value));
else if (pnode.name == "str")
return new Constant(Types.String, pnode.value);
else if (pnode.name == "bool")
return new Constant(Types.Boolean, (pnode.value == "true" ? true : false));
else if (pnode.name == "var")
return new Constant(Types.Variable, pnode.value);
Constant p1, p2;
Constant _p1, _p2;
switch (pnode.childs.Count)
{
case 2:
p1 = Calc(pnode.childs[0]);
p2 = Calc(pnode.childs[1]);
if (p1.type == Types.Variable)
_p1 = varlist[(string)p1.value];
else
_p1 = p1;
if (p2.type == Types.Variable)
_p2 = varlist[(string)p2.value];
else
_p2 = p2;
if (pnode.name == "+")
{
if (_p1.type == Types.String && _p2.type == Types.Number)
return new Constant(Types.String, (string)_p1.value + ((double)_p2.value).ToString());
else if (_p1.type == Types.String && _p2.type == Types.String)
return new Constant(Types.String, (string)_p1.value + (string)_p2.value);
else if (_p1.type == Types.Number && _p2.type == Types.Number)
return new Constant(Types.Number, (double)_p1.value + (double)_p2.value);
else
throw new Exception(string.Format("{0} 演算子を、 {1} 型と {2} 型の演算に使用できません。", pnode.name, _p1.type, _p2.type));
}
else if (pnode.name == "-")
return new Constant(Types.Number, (double)_p1.value - (double)_p2.value);
else if (pnode.name == "*")
{
if (_p1.type == Types.String && _p2.type == Types.Number)
return new Constant(Types.String, (RepeatString((string)_p1.value, (int)(double)_p2.value)));
return new Constant(Types.Number, (double)_p1.value * (double)_p2.value);
}
else if (pnode.name == "/")
return new Constant(Types.Number, (double)_p1.value / (double)_p2.value);
else if (pnode.name == "%")
return new Constant(Types.Number, (double)_p1.value % (double)_p2.value);
else if (pnode.name == "<")
return new Constant(Types.Boolean, ((double)_p1.value < (double)_p2.value) ? true : false);
else if (pnode.name == ">")
return new Constant(Types.Boolean, ((double)_p1.value > (double)_p2.value) ? true : false);
else if (pnode.name == "<=")
return new Constant(Types.Boolean, ((double)_p1.value <= (double)_p2.value) ? true : false);
else if (pnode.name == ">=")
return new Constant(Types.Boolean, ((double)_p1.value >= (double)_p2.value) ? true : false);
else if (pnode.name == "==")
return new Constant(Types.Boolean, ((double)_p1.value == (double)_p2.value) ? true : false);
else if (pnode.name == "!=")
return new Constant(Types.Boolean, ((double)_p1.value != (double)_p2.value) ? true : false);
else if (pnode.name == "<<")
try
{
if ((double)_p1.value - (int)_p1.value != 0 || (double)_p2.value - (int)_p2.value != 0)
throw new Exception(" << 演算は、整数のみ行うことができます。");
else
return new Constant(Types.Number, (int)_p1.value << (int)_p2.value);
}
catch(InvalidCastException)
{
throw new Exception(string.Format("{0} 演算子を、 {1} 型と {2} 型の演算に使用できません。", pnode.name, _p1.type, _p2.type));
}
else if (pnode.name == ">>")
if ((double)_p1.value - (int)_p1.value != 0 || (double)_p2.value - (int)_p2.value != 0)
throw new Exception(" >> 演算は、整数のみ行うことができます。");
else
return new Constant(Types.Number, (int)_p1.value >> (int)_p2.value);
else if (pnode.name == "&")
if ((double)_p1.value - (int)_p1.value != 0 || (double)_p2.value - (int)_p2.value != 0)
throw new Exception(" & 演算は、整数のみ行うことができます。");
else
return new Constant(Types.Number, (int)_p1.value & (int)_p2.value);
else if (pnode.name == "|")
if ((double)_p1.value - (int)_p1.value != 0 || (double)_p2.value - (int)_p2.value != 0)
throw new Exception(" | 演算は、整数のみ行うことができます。");
else
return new Constant(Types.Number, (int)_p1.value | (int)_p2.value);
else if (pnode.name == "^")
if ((double)_p1.value - (int)_p1.value != 0 || (double)_p2.value - (int)_p2.value != 0)
throw new Exception(" ^ 演算は、整数のみ行うことができます。");
else
return new Constant(Types.Number, (int)_p1.value ^ (int)_p2.value);
else if (pnode.name == "=")
{
if (p1.type == Types.Variable)
{
CheckVarExists(p1);
varlist[(string)p1.value] = new Constant(_p2.type, _p2.value);
}
}
else if (pnode.name == "+=")
{
//複合代入演算子に、変数が参照できないときの処理を追加する(キーが存在しないとき)
CheckVarExists(p1);
if (varlist[(string)p1.value].type == Types.String && _p2.type == Types.String)
varlist[(string)p1.value] = new Constant(_p2.type, (string)(varlist[(string)p1.value].value) + (string)_p2.value);
else if (varlist[(string)p1.value].type == Types.String && _p2.type == Types.Number)
varlist[(string)p1.value] = new Constant(varlist[(string)p1.value].type, (string)(varlist[(string)p1.value].value) + (double)_p2.value);
else if (varlist[(string)p1.value].type == Types.Number && _p2.type == Types.Number)
varlist[(string)p1.value] = new Constant(_p2.type, (double)(varlist[(string)p1.value].value) + (double)_p2.value);
else
throw new Exception(string.Format("{0} 演算子を、 {1} 型と {2} 型の演算に使用できません。", pnode.name, _p1.type, _p2.type));
}
else if (pnode.name == "-=")
{
CheckVarExists(p1);
if (varlist[(string)p1.value].type == Types.Number && p2.type == Types.Number)
varlist[(string)p1.value] = new Constant(p2.type, (double)(varlist[(string)p1.value].value) - (double)p2.value);
else
throw new Exception(string.Format("{0} 演算子を、 {1} 型と {2} 型の演算に使用できません。", pnode.name, p1.type, p2.type));
}
else if (pnode.name == "*=")
{
CheckVarExists(p1);
if (varlist[(string)p1.value].type == Types.Number && p2.type == Types.Number)
varlist[(string)p1.value] = new Constant(p2.type, (double)(varlist[(string)p1.value].value) + (double)p2.value);
else if (varlist[(string)p1.value].type == Types.String && p2.type == Types.Number)
varlist[(string)p1.value] = new Constant(varlist[(string)p1.value].type, RepeatString((string)(varlist[(string)p1.value].value), (int)p2.value));
else
throw new Exception(string.Format("{0} 演算子を、 {1} 型と {2} 型の演算に使用できません。", pnode.name, p1.type, p2.type));
}
break;
case 1:
p1 = Calc(pnode.childs[0]);
if (p1.type == Types.Variable)
_p1 = varlist[(string)p1.value];
else
_p1 = p1;
if (pnode.name == "-")
return new Constant(Types.Number, -(double)p1.value);
else if (pnode.name == "~")
if ((double)p1.value - (int)p1.value != 0)
throw new Exception("~ 演算は、整数のみ行うことができます。");
else
return new Constant(Types.Number, ~(int)p1.value);
else if (pnode.name == "!")
{
if ((double)p1.value != 0)
return new Constant(Types.Number, 1);
else
return new Constant(Types.Number, 0);
}
break;
default:
throw new Exception(string.Format("{0}つの項をとる演算子はありません。", pnode.childs.Count));
}
throw new Exception(string.Format("{0}つの項をとる、\"{1}\" 演算子はありません。", pnode.childs.Count, pnode.name));
}
public static string RepeatString(string s, int count)
{
System.Text.StringBuilder buf =
new System.Text.StringBuilder(s.Length * count);
for (int i = 0; i < count; i++)
{
buf.Append(s);
}
return buf.ToString();
}
static void ConstExpression(string[] intoken)
{
token = intoken;
ix = 0;
Node expr = SetAssignment();
Constant cst = Calc(expr);
Console.WriteLine(cst.type + " " + cst.value);
}
/// <summary>
/// 指定した Constant が変数を表すか、表すならその変数が存在するかどうか確認し、問題があれば例外を投げます。
/// </summary>
/// <param name="vardata">チェックする Constant 構造体。</param>
static void CheckVarExists(Constant vardata)
{
if (vardata.type != Types.Variable)
throw new Exception("左辺は変数を表しません。");
if (!varlist.ContainsKey((string)vardata.value))
throw new Exception(string.Format("変数 {0} は宣言されていません。", (string)vardata.value));
}
}
struct Node
{
public string name;
public List<Node> childs;
public string value;
}
/*struct Variable
{
//public Types type;
public string name;
public Constant value;
public void SetValue(string nm, Constant con)
{
name = nm;
if (this.value.type == con.type || this.value.type == Types.Null)
{
this.value.type = con.type;
this.value = con;
}
else
{
if (this.value.type == Types.Number && con.type == Types.String)
{
con.value = double.Parse((string)con.value);
}
else if (this.value.type == Types.String && con.type == Types.Number)
{
con.value = ((int)con.value).ToString();
}
else
throw new Exception(string.Format("{0} から {1} への変換はできません。", con.type.ToString(), this.value.type.ToString()));
}
}
}*/
struct Constant
{
public Types type;
public object value;
public Constant(Types t, object val)
{
type = t;
switch (t)
{
case Types.Number:
if (!(val is double || val is int))
throw new Exception("型が一致しません。");
break;
case Types.Boolean:
if (!(val is bool))
throw new Exception("型が一致しません。");
break;
case Types.String:
if (!(val is string))
throw new Exception("型が一致しません。");
break;
}
value = val;
}
}
enum Types
{
Null, Number, String, Boolean, Variable
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment