関数定義の構文解析を実�
This commit is contained in:
@@ -18,6 +18,45 @@ class Scope
|
|||||||
this.continueAddr = continueAddr;
|
this.continueAddr = continueAddr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
class Function
|
||||||
|
{
|
||||||
|
int address;
|
||||||
|
wstring name;
|
||||||
|
int argumentIndex;
|
||||||
|
int variableIndex;
|
||||||
|
int[wstring] variable;
|
||||||
|
int[wstring] label;
|
||||||
|
this(int address, wstring name)
|
||||||
|
{
|
||||||
|
this.address = address;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
int getLocalVarIndex(wstring name)
|
||||||
|
{
|
||||||
|
int var = this.variable.get(name, 0);
|
||||||
|
if(var == 0)
|
||||||
|
{
|
||||||
|
//local変数をあたる
|
||||||
|
//それでもだめならOPTION STRICTならエラー
|
||||||
|
this.variable[name] = var = ++variableIndex;
|
||||||
|
}
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
int defineLocalVarIndex(wstring name)
|
||||||
|
{
|
||||||
|
int var = this.variable.get(name, 0);
|
||||||
|
if(var == 0)
|
||||||
|
{
|
||||||
|
this.variable[name] = var = ++variableIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//error:二重定義
|
||||||
|
throw new DuplicateVariable();
|
||||||
|
}
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
}
|
||||||
class Compiler
|
class Compiler
|
||||||
{
|
{
|
||||||
ValueType getType(wstring name)
|
ValueType getType(wstring name)
|
||||||
@@ -45,6 +84,7 @@ class Compiler
|
|||||||
Code[] code;
|
Code[] code;
|
||||||
int[wstring] global;
|
int[wstring] global;
|
||||||
int[wstring] globalLabel;
|
int[wstring] globalLabel;
|
||||||
|
Function[wstring] functions;
|
||||||
int globalIndex = 0;
|
int globalIndex = 0;
|
||||||
void genCode(Code c)
|
void genCode(Code c)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -63,6 +63,12 @@ END
|
|||||||
@A
|
@A
|
||||||
?\"SUBROUTINE TEST\"
|
?\"SUBROUTINE TEST\"
|
||||||
RETURN
|
RETURN
|
||||||
|
DEF A()
|
||||||
|
?\"FUNCTION A\"
|
||||||
|
END
|
||||||
|
DEF B(A,B[],C)
|
||||||
|
?\"FUNCTION B\"
|
||||||
|
END
|
||||||
");
|
");
|
||||||
version(none) auto parser = new Parser(readText("FIZZBUZZ.TXT").to!wstring);
|
version(none) auto parser = new Parser(readText("FIZZBUZZ.TXT").to!wstring);
|
||||||
auto vm = parser.compile();
|
auto vm = parser.compile();
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ enum NodeType
|
|||||||
DefineVariable,
|
DefineVariable,
|
||||||
DefineArray,
|
DefineArray,
|
||||||
ArrayAssign,
|
ArrayAssign,
|
||||||
|
DefineFunction,
|
||||||
}
|
}
|
||||||
abstract class Node
|
abstract class Node
|
||||||
{
|
{
|
||||||
@@ -359,3 +360,23 @@ class ArrayAssign : Statement
|
|||||||
this.assignExpression = assign;
|
this.assignExpression = assign;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
class DefineFunction : Statement
|
||||||
|
{
|
||||||
|
wstring[] arguments;
|
||||||
|
wstring[] outArguments;
|
||||||
|
wstring name;
|
||||||
|
Statements functionBody;
|
||||||
|
this(wstring name)
|
||||||
|
{
|
||||||
|
this.type = NodeType.DefineFunction;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
void addArgument(wstring name)
|
||||||
|
{
|
||||||
|
this.arguments ~= name;
|
||||||
|
}
|
||||||
|
void addOutArgument(wstring name)
|
||||||
|
{
|
||||||
|
this.outArguments ~= name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ class Lexical
|
|||||||
reserved["CONTINUE"] = TokenType.Continue;
|
reserved["CONTINUE"] = TokenType.Continue;
|
||||||
reserved["VAR"] = TokenType.Var;
|
reserved["VAR"] = TokenType.Var;
|
||||||
reserved["DIM"] = TokenType.Var;
|
reserved["DIM"] = TokenType.Var;
|
||||||
|
reserved["DEF"] = TokenType.Def;
|
||||||
reserved.rehash();
|
reserved.rehash();
|
||||||
line = 1;
|
line = 1;
|
||||||
}
|
}
|
||||||
@@ -402,8 +403,112 @@ class Parser
|
|||||||
auto statements = new Statements();
|
auto statements = new Statements();
|
||||||
while(!lex.empty())
|
while(!lex.empty())
|
||||||
{
|
{
|
||||||
//if token == DEF
|
auto token = lex.front();
|
||||||
//
|
Statement statement;
|
||||||
|
if(token.type == TokenType.Def)
|
||||||
|
{
|
||||||
|
statement = defineFunction();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
statement = this.statement();
|
||||||
|
}
|
||||||
|
if(statement != Statement.NOP)
|
||||||
|
{
|
||||||
|
statements.addStatement(statement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return statements;
|
||||||
|
}
|
||||||
|
wstring getFunctionArgument()
|
||||||
|
{
|
||||||
|
auto token = lex.front();
|
||||||
|
if(token.type != TokenType.Iden)
|
||||||
|
{
|
||||||
|
syntaxError();
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
lex.popFront();
|
||||||
|
if(lex.front().type == TokenType.LBracket)
|
||||||
|
{
|
||||||
|
lex.popFront();
|
||||||
|
if(lex.front().type != TokenType.RBracket)
|
||||||
|
{
|
||||||
|
syntaxError();
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
lex.popFront();
|
||||||
|
}
|
||||||
|
return token.value.stringValue;
|
||||||
|
}
|
||||||
|
DefineFunction defineFunction()
|
||||||
|
{
|
||||||
|
lex.popFront();
|
||||||
|
auto token = lex.front();
|
||||||
|
if(token.type != TokenType.Iden)
|
||||||
|
{
|
||||||
|
syntaxError();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
DefineFunction node = new DefineFunction(token.value.stringValue);
|
||||||
|
lex.popFront();
|
||||||
|
token = lex.front();
|
||||||
|
if(token.type == TokenType.LParen)
|
||||||
|
{
|
||||||
|
lex.popFront();
|
||||||
|
//MEMO:引数に[]を付けようが扱いは同一
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
if(lex.front().type == TokenType.RParen)
|
||||||
|
{
|
||||||
|
lex.popFront();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
wstring arg = getFunctionArgument();
|
||||||
|
if(arg.length == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
node.addArgument(arg);
|
||||||
|
token = lex.front();
|
||||||
|
if(token.type == TokenType.Comma)
|
||||||
|
{
|
||||||
|
lex.popFront();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//MEMO:引数に[]を付けようが扱いは同一
|
||||||
|
if(token.type == TokenType.RParen)
|
||||||
|
{
|
||||||
|
lex.popFront();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
syntaxError();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//void関数にRETURN核とsyntaxerror
|
||||||
|
writeln("NOTIMPL:DEF VOID");
|
||||||
|
syntaxError();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
node.functionBody = functionStatements();
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
Statements functionStatements()
|
||||||
|
{
|
||||||
|
auto statements = new Statements();
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
auto type = lex.front().type;
|
||||||
|
if(type == TokenType.End) break;
|
||||||
|
if(lex.empty())
|
||||||
|
{
|
||||||
|
//TODO:DEF without edn
|
||||||
|
syntaxError();
|
||||||
|
break;
|
||||||
|
}
|
||||||
auto statement = statement();
|
auto statement = statement();
|
||||||
if(statement != Statement.NOP)
|
if(statement != Statement.NOP)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ enum TokenType
|
|||||||
Var,
|
Var,
|
||||||
LBracket,//[
|
LBracket,//[
|
||||||
RBracket,//]
|
RBracket,//]
|
||||||
|
Def,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Token
|
struct Token
|
||||||
|
|||||||
Reference in New Issue
Block a user