1
0

INPUTを実装.

This commit is contained in:
otya128
2015-08-19 11:28:53 +09:00
parent f682bec0f9
commit c75b129567
8 changed files with 324 additions and 5 deletions

View File

@@ -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 />

View File

@@ -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,

View File

@@ -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);
}
}

View File

@@ -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);
} }

View File

@@ -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;
}
}

View File

@@ -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();

View File

@@ -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;

View File

@@ -62,6 +62,7 @@ enum TokenType
Read, Read,
Restore, Restore,
On, On,
Input,
} }
struct Token struct Token