INPUTを実装.
This commit is contained in:
@@ -89,7 +89,7 @@
|
|||||||
<cv2pdbOptions />
|
<cv2pdbOptions />
|
||||||
<objfiles />
|
<objfiles />
|
||||||
<linkswitches />
|
<linkswitches />
|
||||||
<libfiles>DerelictSDL2.lib;DerelictUtil.lib;DerelictGL3.lib</libfiles>
|
<libfiles>DerelictSDL2.lib;DerelictUtil.lib;DerelictGL3.lib;kernel32.lib</libfiles>
|
||||||
<libpaths>$(DMDInstallDir)windows\lib\</libpaths>
|
<libpaths>$(DMDInstallDir)windows\lib\</libpaths>
|
||||||
<deffile />
|
<deffile />
|
||||||
<resfile />
|
<resfile />
|
||||||
|
|||||||
@@ -79,6 +79,8 @@ DEF ONGOSUBTEST
|
|||||||
RETURN
|
RETURN
|
||||||
@4
|
@4
|
||||||
END
|
END
|
||||||
|
INPUT "A";INPUT$
|
||||||
|
?INPUT$
|
||||||
@DATA_1
|
@DATA_1
|
||||||
DATA "A",1,2,3,4
|
DATA "A",1,2,3,4
|
||||||
LOCATE 10,
|
LOCATE 10,
|
||||||
|
|||||||
@@ -1036,3 +1036,67 @@ class OnGosub : OnBase
|
|||||||
vm.pc = index - 1;
|
vm.pc = index - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
import std.string;
|
||||||
|
class InputCode : Code
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
ValueType[] type;
|
||||||
|
Value[] output;
|
||||||
|
this(int count)
|
||||||
|
{
|
||||||
|
this.count = count;
|
||||||
|
type = new ValueType[count];
|
||||||
|
output = new Value[count];
|
||||||
|
}
|
||||||
|
override void execute(VM vm)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
Value v;
|
||||||
|
vm.pop(v);
|
||||||
|
type[i] = v.type;
|
||||||
|
}
|
||||||
|
bool error;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if(error)
|
||||||
|
{
|
||||||
|
vm.petitcomputer.printConsoleString("?Redo from start \n");
|
||||||
|
}
|
||||||
|
wstring input = vm.petitcomputer.input("", false);
|
||||||
|
wstring[] split = input.split(",");
|
||||||
|
error = false;
|
||||||
|
if(split.length < count)
|
||||||
|
{
|
||||||
|
error = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach(i, s; split)
|
||||||
|
{
|
||||||
|
if(i >= count)
|
||||||
|
{
|
||||||
|
//指定数超えたら無視
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//先頭のスペースは無視する
|
||||||
|
munch(s, " ");
|
||||||
|
if(type[i] == ValueType.Double || type[i] == ValueType.Integer)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
vm.push(Value(to!double(s)));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vm.push(Value(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -198,6 +198,23 @@ class Compiler
|
|||||||
}
|
}
|
||||||
code ~= new PopG(getGlobalVarIndex(name));
|
code ~= new PopG(getGlobalVarIndex(name));
|
||||||
}
|
}
|
||||||
|
void getVarIndex(wstring name, Scope sc, out int index, out bool isLocal)
|
||||||
|
{
|
||||||
|
auto global = hasGlobalVarIndex(name);
|
||||||
|
if(sc.func)
|
||||||
|
isLocal = sc.func.hasLocalVarIndex(name) != 0;
|
||||||
|
if(sc.func && isLocal)
|
||||||
|
{
|
||||||
|
index = sc.func.getLocalVarIndex(name, this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(global)
|
||||||
|
{
|
||||||
|
index = global;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
index = getGlobalVarIndex(name);
|
||||||
|
}
|
||||||
void genCodeOP(TokenType op)
|
void genCodeOP(TokenType op)
|
||||||
{
|
{
|
||||||
code ~= new Operate(op);
|
code ~= new Operate(op);
|
||||||
@@ -386,6 +403,47 @@ class Compiler
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void compilePopVar(Expression expr, Scope sc)
|
||||||
|
{
|
||||||
|
switch(expr.type)
|
||||||
|
{
|
||||||
|
case NodeType.Variable:
|
||||||
|
{
|
||||||
|
auto var = cast(Variable)expr;
|
||||||
|
int index;
|
||||||
|
bool local;
|
||||||
|
getVarIndex(var.name, sc, index, local);
|
||||||
|
genCode(local ? new PopL(index) : new PopG(index));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NodeType.BinaryOperator:
|
||||||
|
{
|
||||||
|
auto binop = cast(BinaryOperator)expr;
|
||||||
|
compileExpression(binop.item2, sc);
|
||||||
|
if(binop.operator == TokenType.LBracket)
|
||||||
|
{
|
||||||
|
IndexExpressions ie = cast(IndexExpressions)binop.item2;
|
||||||
|
auto var = cast(Variable)binop.item1;
|
||||||
|
int index;
|
||||||
|
bool local;
|
||||||
|
getVarIndex(var.name, sc, index, local);
|
||||||
|
if(ie)
|
||||||
|
{
|
||||||
|
genCode(new PopArray(index, ie.expressions.length, local));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
genCode(new PopArray(index, 1, local));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
stderr.writeln("ERROR");
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
void compileIf(If node, Scope sc)
|
void compileIf(If node, Scope sc)
|
||||||
{
|
{
|
||||||
compileExpression(node.condition, sc);
|
compileExpression(node.condition, sc);
|
||||||
@@ -539,6 +597,27 @@ class Compiler
|
|||||||
compileExpression(on.condition, sc);
|
compileExpression(on.condition, sc);
|
||||||
genCode(new OnS(on.labels, on.isGosub, sc));
|
genCode(new OnS(on.labels, on.isGosub, sc));
|
||||||
}
|
}
|
||||||
|
void compileInput(Input input, Scope sc)
|
||||||
|
{
|
||||||
|
if(input.question)
|
||||||
|
{
|
||||||
|
genCodeImm(Value("?\n"));
|
||||||
|
}
|
||||||
|
if(input.message)
|
||||||
|
{
|
||||||
|
compileExpression(input.message, sc);
|
||||||
|
}
|
||||||
|
genCode(new PrintCode((input.question ? 1 : 0) + (input.message ? 1 : 0)));
|
||||||
|
foreach_reverse(i; input.variables)
|
||||||
|
{
|
||||||
|
compileExpression(i, sc);
|
||||||
|
}
|
||||||
|
genCode(new InputCode(input.variables.length));
|
||||||
|
foreach_reverse(i; input.variables)
|
||||||
|
{
|
||||||
|
compilePopVar(i, sc);
|
||||||
|
}
|
||||||
|
}
|
||||||
void compileStatement(Statement i, Scope s)
|
void compileStatement(Statement i, Scope s)
|
||||||
{
|
{
|
||||||
switch(i.type)
|
switch(i.type)
|
||||||
@@ -705,6 +784,9 @@ class Compiler
|
|||||||
case NodeType.On:
|
case NodeType.On:
|
||||||
compileOn(cast(On)i, s);
|
compileOn(cast(On)i, s);
|
||||||
break;
|
break;
|
||||||
|
case NodeType.Input:
|
||||||
|
compileInput(cast(Input)i, s);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
stderr.writeln("Compile:NotImpl ", i.type);
|
stderr.writeln("Compile:NotImpl ", i.type);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ enum NodeType
|
|||||||
Read,
|
Read,
|
||||||
Restore,
|
Restore,
|
||||||
On,
|
On,
|
||||||
|
Input,
|
||||||
}
|
}
|
||||||
abstract class Node
|
abstract class Node
|
||||||
{
|
{
|
||||||
@@ -466,3 +467,20 @@ class On : Statement
|
|||||||
this.labels ~= label;
|
this.labels ~= label;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
class Input : Statement
|
||||||
|
{
|
||||||
|
Expression message;
|
||||||
|
bool question;
|
||||||
|
Expression[] variables;
|
||||||
|
this(Expression message, bool question)
|
||||||
|
{
|
||||||
|
this.message = message;
|
||||||
|
this.question = question;
|
||||||
|
this.variables = new Expression[0];
|
||||||
|
this.type = NodeType.Input;
|
||||||
|
}
|
||||||
|
void addVariable(Expression lvalue)
|
||||||
|
{
|
||||||
|
variables ~= lvalue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ class Lexical
|
|||||||
reserved["READ"] = TokenType.Read;
|
reserved["READ"] = TokenType.Read;
|
||||||
reserved["RESTORE"] = TokenType.Restore;
|
reserved["RESTORE"] = TokenType.Restore;
|
||||||
reserved["ON"] = TokenType.On;
|
reserved["ON"] = TokenType.On;
|
||||||
|
reserved["INPUT"] = TokenType.Input;
|
||||||
reserved.rehash();
|
reserved.rehash();
|
||||||
line = 1;
|
line = 1;
|
||||||
}
|
}
|
||||||
@@ -789,6 +790,8 @@ class Parser
|
|||||||
case TokenType.On:
|
case TokenType.On:
|
||||||
node = onStatement();
|
node = onStatement();
|
||||||
break;
|
break;
|
||||||
|
case TokenType.Input:
|
||||||
|
return inputStatement();
|
||||||
default:
|
default:
|
||||||
syntaxError();
|
syntaxError();
|
||||||
break;
|
break;
|
||||||
@@ -796,6 +799,60 @@ class Parser
|
|||||||
lex.popFront();
|
lex.popFront();
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
//左辺値か
|
||||||
|
bool isLValue(Expression expr)
|
||||||
|
{
|
||||||
|
if(expr.type == NodeType.Variable)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(expr.type == NodeType.BinaryOperator)
|
||||||
|
{
|
||||||
|
auto op = cast(BinaryOperator)expr;
|
||||||
|
if(!isLValue(op.item1)) return false;
|
||||||
|
return op.operator == TokenType.LBracket;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Input inputStatement()
|
||||||
|
{
|
||||||
|
lex.popFront();
|
||||||
|
Expression message = expression();
|
||||||
|
if(!message)
|
||||||
|
{
|
||||||
|
syntaxError();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
auto token = lex.front();
|
||||||
|
if(token.type == TokenType.Semicolon || token.type == TokenType.Comma)
|
||||||
|
{
|
||||||
|
Input input = new Input(message, token.type == TokenType.Semicolon);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
lex.popFront();
|
||||||
|
auto expr = expression();
|
||||||
|
if(!isLValue(expr))
|
||||||
|
{
|
||||||
|
syntaxError();
|
||||||
|
}
|
||||||
|
input.addVariable(expr);
|
||||||
|
lex.popFront();
|
||||||
|
token = lex.front();
|
||||||
|
} while(token.type == TokenType.Comma);
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!isLValue(message))
|
||||||
|
{
|
||||||
|
syntaxError();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Input input = new Input(null, true);
|
||||||
|
input.addVariable(message);
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
}
|
||||||
On onStatement()
|
On onStatement()
|
||||||
{
|
{
|
||||||
lex.popFront();
|
lex.popFront();
|
||||||
|
|||||||
@@ -55,6 +55,14 @@ class GraphicPage
|
|||||||
texture_format, GL_UNSIGNED_BYTE, surface.pixels );
|
texture_format, GL_UNSIGNED_BYTE, surface.pixels );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
version(Windows)
|
||||||
|
{
|
||||||
|
extern (Windows) static void* LoadLibraryA(in char*);
|
||||||
|
extern (Windows) static bool FreeLibrary(void*);
|
||||||
|
extern (Windows) static void* GetProcAddress(void*, in char*);
|
||||||
|
alias extern (Windows) void* function(void*, void*) ImmAssociateContext;
|
||||||
|
alias extern (Windows) int function(int) ImmDisableIME;
|
||||||
|
}
|
||||||
class PetitComputer
|
class PetitComputer
|
||||||
{
|
{
|
||||||
this()
|
this()
|
||||||
@@ -396,14 +404,30 @@ class PetitComputer
|
|||||||
vsyncCount = 0;
|
vsyncCount = 0;
|
||||||
vsyncFrame = f;
|
vsyncFrame = f;
|
||||||
}
|
}
|
||||||
|
Mutex keybuffermutex;
|
||||||
int keybufferpos;
|
int keybufferpos;
|
||||||
|
int keybufferlen;
|
||||||
//解析した結果キー入力のバッファは127くらい
|
//解析した結果キー入力のバッファは127くらい
|
||||||
wchar[] keybuffer = new wchar[127];
|
wchar[] keybuffer = new wchar[128];
|
||||||
|
void sendKey(wchar key)
|
||||||
|
{
|
||||||
|
keybuffer[keybufferpos] = cast(wchar)key;
|
||||||
|
keybufferlen++;
|
||||||
|
if(keybufferlen > keybuffer.length)
|
||||||
|
keybufferlen = keybuffer.length;
|
||||||
|
keybufferpos = (keybufferpos + 1) % keybuffer.length;
|
||||||
|
}
|
||||||
void render()
|
void render()
|
||||||
{
|
{
|
||||||
bool renderprofile;
|
bool renderprofile;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
version(Windows)
|
||||||
|
{
|
||||||
|
auto imm32 = LoadLibraryA("imm32.dll".toStringz);
|
||||||
|
ImmDisableIME ImmDisableIME = cast(ImmDisableIME)GetProcAddress(imm32, "ImmDisableIME".toStringz);
|
||||||
|
ImmDisableIME(0);
|
||||||
|
}
|
||||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||||
window = SDL_CreateWindow("SMILEBASIC", SDL_WINDOWPOS_UNDEFINED,
|
window = SDL_CreateWindow("SMILEBASIC", SDL_WINDOWPOS_UNDEFINED,
|
||||||
SDL_WINDOWPOS_UNDEFINED, 400, 240,
|
SDL_WINDOWPOS_UNDEFINED, 400, 240,
|
||||||
@@ -417,6 +441,17 @@ class PetitComputer
|
|||||||
glViewport(0, 0, 400, 240);
|
glViewport(0, 0, 400, 240);
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
version(Windows)
|
||||||
|
{
|
||||||
|
SDL_SysWMinfo wm;
|
||||||
|
if(SDL_GetWindowWMInfo(window, &wm))
|
||||||
|
{
|
||||||
|
ImmAssociateContext ImmAssociateContext = cast(ImmAssociateContext)GetProcAddress(imm32, "ImmAssociateContext".toStringz);
|
||||||
|
auto aa = wm.info.win.window;
|
||||||
|
auto c = ImmAssociateContext(wm.info.win.window, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
auto profile = SDL_GetTicks();
|
auto profile = SDL_GetTicks();
|
||||||
@@ -435,8 +470,27 @@ class PetitComputer
|
|||||||
return;
|
return;
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
auto key = event.key.keysym.sym;
|
auto key = event.key.keysym.sym;
|
||||||
keybuffer[keybufferpos] = cast(wchar)key;
|
if(key == SDLK_BACKSPACE)
|
||||||
keybufferpos = (keybufferpos + 1) % keybuffer.length;
|
{
|
||||||
|
keybuffermutex.lock();
|
||||||
|
sendKey('\u0008');
|
||||||
|
keybuffermutex.unlock();
|
||||||
|
}
|
||||||
|
if(key == SDLK_RETURN)
|
||||||
|
{
|
||||||
|
keybuffermutex.lock();
|
||||||
|
sendKey('\u000D');
|
||||||
|
keybuffermutex.unlock();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_TEXTINPUT:
|
||||||
|
auto text = event.text.text[0..event.text.text.indexOf('\0')].to!wstring;
|
||||||
|
keybuffermutex.lock();
|
||||||
|
foreach(wchar key; text)
|
||||||
|
{
|
||||||
|
sendKey(key);
|
||||||
|
}
|
||||||
|
keybuffermutex.unlock();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -511,6 +565,7 @@ GOTO @LOOP`*/
|
|||||||
bool running = true;
|
bool running = true;
|
||||||
vm.init(this);
|
vm.init(this);
|
||||||
consolem = new Mutex();
|
consolem = new Mutex();
|
||||||
|
keybuffermutex = new Mutex();
|
||||||
core.thread.Thread thread = new core.thread.Thread(&render);
|
core.thread.Thread thread = new core.thread.Thread(&render);
|
||||||
thread.start();
|
thread.start();
|
||||||
auto startTicks = SDL_GetTicks();
|
auto startTicks = SDL_GetTicks();
|
||||||
@@ -554,10 +609,50 @@ GOTO @LOOP`*/
|
|||||||
SDL_DestroyWindow(window);
|
SDL_DestroyWindow(window);
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
}
|
}
|
||||||
|
void clearKeyBuffer()
|
||||||
|
{
|
||||||
|
keybuffermutex.lock();
|
||||||
|
scope(exit) keybuffermutex.unlock();
|
||||||
|
keybufferpos = 0;
|
||||||
|
keybufferlen = 0;
|
||||||
|
}
|
||||||
wstring input(wstring prompt, bool useClipBoard)
|
wstring input(wstring prompt, bool useClipBoard)
|
||||||
{
|
{
|
||||||
printConsole(prompt);
|
printConsole(prompt);
|
||||||
return "";
|
clearKeyBuffer();
|
||||||
|
wstring buffer;
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
auto oldpos = keybufferpos;
|
||||||
|
while(oldpos == keybufferpos)
|
||||||
|
{
|
||||||
|
SDL_Delay(4);//適当 ストレスを感じないくらい
|
||||||
|
}
|
||||||
|
auto kbp = keybufferpos;
|
||||||
|
auto len = kbp - oldpos;
|
||||||
|
if(len < 0)
|
||||||
|
{
|
||||||
|
//arienai
|
||||||
|
kbp = oldpos;
|
||||||
|
}
|
||||||
|
wchar k;
|
||||||
|
foreach(key; keybuffer[oldpos..kbp])
|
||||||
|
{
|
||||||
|
printConsole(key);
|
||||||
|
if(key == '\r')
|
||||||
|
{
|
||||||
|
k = key;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buffer ~= key;
|
||||||
|
}
|
||||||
|
clearKeyBuffer();
|
||||||
|
if(k == '\r')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
}
|
}
|
||||||
int CSRX;
|
int CSRX;
|
||||||
int CSRY;
|
int CSRY;
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ enum TokenType
|
|||||||
Read,
|
Read,
|
||||||
Restore,
|
Restore,
|
||||||
On,
|
On,
|
||||||
|
Input,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Token
|
struct Token
|
||||||
|
|||||||
Reference in New Issue
Block a user