ARGENTO CUORE

Category : Scalable Language Scala

--.--.--[--] スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

2010.06.19[土] バイト列を整数値に

変換用のメソッドってあるのかな。見当たらなかった……。

private def getIntFromByteArray(bytes:Array[Byte]):Int = {
return (((bytes(0) & 0xFF) << 24)
| ((bytes(1) & 0xFF) << 16)
| ((bytes(2) & 0xFF) << 8)
| (bytes(3) & 0xFF))
}
スポンサーサイト

2010.06.12[土] 再帰下降法

再帰加工法で計算するクラスを作ってみた。
とりあえずできたっぽいかなー……。

↓を参考にしましたー。
http://www.hakkaku.net/articles/20090128-304

package com.gmail.cuore.argento.UO

/**
* RecursiveDescentParser
*/
object RDParser {
var data:Array[Byte] = null
var count = 0
var isContinue = true

//println("answer=" + expression())
private def getCurrentValue():Byte = {
if(count < data.length){
var ret = data(count)
count += 1
return ret
}
isContinue = false
return 0
}

private def expr3():Int = {
var num = getCurrentValue()
if(num == KEY.NUMBER){
val ret = Calc.getInt(Arrays.copyOfRange(data, count, count+4))
count+=4
return ret
}else if(num == KEY.LPAREN){
val answer = expr1()
val res = getCurrentValue()
if(isContinue){
if(res != KEY.RPAREN){
System.err.println("Right parenthesis not found.")
}
}
return answer
}

return num
}

private def expr2():Int = {
var num = expr3()
var res = getCurrentValue()
if(res == KEY.ASTERISK){
num *= expr3()
}else if(res == KEY.SLASH){
num /= expr3()
}else{
count -= 1
return num
}
return num
}

private def expr1():Int = {
var num = expr2()
val res = getCurrentValue()
if(res == KEY.PLUS){
num += expr2()
}else if(res == KEY.MINUS){
num -= expr2()
}else if(res == KEY.ASTERISK || res == KEY.SLASH){
count -= 1
return num
}else{
return num
}
return num
}

def expression(d:Array[Byte]):Int = {
data = d
isContinue = true
count = 0
return expr1()
}
}

2010.06.10[木] Synthを触る

Javaのルックアンドフィールは、xmlでテーマを記述することで、デザイナでも簡単にテーマを作成できる。
らしいので、Scalaから触ってみた(もう二度とJavaを触ることはないかもしれない……)。

javax.swing.UIManager
javax.swing.plaf.synth.SynthLookAndFeel

上記2つのパッケージをインポートした上で、
val synth = new SynthLookAndFeel()
synth.load(AppClass.getClass().getResourceAsStream("theme.xml"), AppClass.getClass())
UIManager.setLookAndFeel(synth)

とすることで、テーマを適用できる。テーマはxmlファイルで記述するので、getResourceAsStream(xmlファイル名)でロードする。
theme.xmlは以下のように書く。
<synth>
<style id="default">
<font name="Sans-serif" size="20" />
<state>
<color value="#FFFFFF" type="FOREGROUND" />
<imagePainter method="buttonBackground" path="hoge.png"
sourceInsets="10 10 10 10" />
</state>
</style>
<style id="internal_frame">
<opaque value="true" />
<imageIcon id="InternalFrameIcon" path="icon.png" />
<property key="InternalFrame.icon" type="idref" value="InternalFrameIcon" />

<state>
<color value="#FF00FF" type="BACKGROUND" />
</state>
<imagePainter method="internalFrameBorder" path="waku.png"
sourceInsets="5 5 5 5" paintCenter="true" />
<insets top="0" left="0" bottom="12" right="0" />
</style>
<style id="internal_frame_title">
<insets top="0" left="16" bottom="3" right="0" />
<property key="InternalFrameTitlePane.titleSpacing" type="integer" value="7" />
<property key="InternalFrameTitlePane.buttonSpacing" type="integer" value="0" />
<font name="梅ゴシック" size="10" />
<state>
<color value="#FF00FF" type="BACKGROUND" />
</state>

<imageIcon id="InternalFrameCloseButtonIcon" path="close_button.png" />
<property key="InternalFrameTitlePane.closeIcon" type="idref" value="InternalFrameCloseButtonIcon" />
<imageIcon id="InternalFrameMaximizeButtonIcon" path="maximize_button.png" />
<property key="InternalFrameTitlePane.maximizeIcon" type="idref" value="InternalFrameMaximizeButtonIcon" />
<imageIcon id="InternalFrameMinimizeButtonIcon" path="minimize_button.png" />
<property key="InternalFrameTitlePane.minimizeIcon" type="idref" value="InternalFrameMinimizeButtonIcon" />
<imageIcon id="InternalFrameIconifyButtonIcon" path="iconify_button.png" />
<property key="InternalFrameTitlePane.iconifyIcon" type="idref" value="InternalFrameIconifyButtonIcon" />
</style>
<style id="InternalFrameMaximizeButtonStyle">
<insets top="0" left="0" right="0" bottom="0" />
</style>
<bind style="default" type="region" key="Button" />
<bind style="internal_frame" type="region" key="InternalFrame" />
<bind style="internal_frame_title" type="region" key="InternalFrameTitlePane" />
<bidd style="InternalFrameMaximizeButtonStyle" type="name" key="InternalframeTitlePane.maximizeButton" />
</synth>


ウインドウフレームのデザインを変えてみたかったので、JInternalFrameに対してのテーマを作成してみた。本当は他にも色々設定しないといけない項目があるけど(例えばボタンデザインであれば、オーバーしたとき、クリックしたときetc...)、それはちょっとずついじってみようと思う。

参考
■sun、synthのページ
http://java.sun.com/docs/books/tutorial/uiswing/lookandfeel/synth.html

■コンポーネントプロパティ
http://java.sun.com/javase/7/docs/api/javax/swing/plaf/synth/doc-files/componentProperties.html

■リージョン
http://java.sun.com/javase/ja/6/docs/ja/api/javax/swing/plaf/synth/Region.html

■IBMのSynthページ
http://www.ibm.com/developerworks/jp/java/library/j-synth/

■EaSynth内のSynthについて取り扱ったページ
http://www.easynth.com/articles/005.htm

■Sophieプロジェクト内のWiki
http://sophie2.org/trac/wiki/AUTHOR_APP_TUNING

2010.06.03[木] ただコードを貼り付けてみる

字句解析?を書き直してみた。当社比1/10くらいまでnewが減ったよ! 
でもまだnewしてるよ……。字句解析、全行1回済ませば終わりだし、この部分はあまりこだわらなくても平気かなー……。

class ScanLine {
val LINE_COMMENT = KEY.SHARP
val COMMENT_NONE = 0
val COMMENT_BEGIN = 1
val COMMENT_END = 2

var count = 0 //有効文字数
var comment_mode = 0 //コメントモード
val data = new Array[Byte](PREF.LINE_MAX_BUFF)

def init():Unit = {
if(comment_mode == LINE_COMMENT){
comment_mode = COMMENT_NONE
}
if(count > 0) count = 0
}

def set(ch:Int):Unit = {
checkComment(ch)
if(comment_mode == COMMENT_NONE){
//スペース以外の時、処理を実行(ただし、文字列の場合にはスペースの時も実行)
if(ch != KEY.SPACE || isString == true){
if(checkLine(ch)){
addData(KEY.NL)
}
}
}else if(comment_mode == COMMENT_END){
comment_mode = COMMENT_NONE
}
}

def getData():Array[Byte] = {
if(count > 0){
return data
}else{
return null
}
}

//文字列を保持するバッファ
val keyword_buffer = new Array[Byte](100)
//文字数をカウントする変数
var keyword_count = 0
//有効な文字が存在する場合はtrue
var isExist = false
//""で囲まれた文字リテラルの読み込み中はtrue
var isString = false

//一文字を得るためのString変数
var str:String = null
//一文字をUTF-8のバイト列に変換したものを入れる
var bytes:Array[Byte] = null

/**
* checkLine
* 行の文字列を貯めてチェックし、もし有効な文字(命令や変数や計算)が存在するならtrueを返す
*/
def checkLine(ch:Int):Boolean = {
str = String.valueOf(ch.asInstanceOf[Char])
bytes = str.getBytes("UTF-8")

if(isSplitter(ch)){
//区切り文字で、文字列内ではない場合
if(keyword_count > 0){
val key = new String(keyword_buffer, 0, keyword_count)
//キーワードに合致する場合は、それに対応するバイトコードをセット
if(!isOrder(key)){
if(isNumber(keyword_buffer(0))) addData(KEY.NUMBER) //数値
if(isVariable(keyword_buffer(0))) addData(KEY.VARIABLE) //変数
if(data(count-1) == KEY.NUMBER){
setNumber(Integer.valueOf(key).asInstanceOf[Int])//数値をバイト列に変換
}else{
for(n <- 0 until keyword_count){
addData(keyword_buffer(n)) //変数名はdataに値をそのまま入れる
}
}
}
//改行、終端でない場合はセット
if(!isEndOfLine(bytes(0))) addData(bytes(0))
keyword_count = 0
}else{
//文字列中ではなく、ブロック{}であった場合は、1文字だけでもそのままデータとしてセットする
if(!isString && isBlock(bytes(0))){
addData(bytes(0))
isExist = true
}
}
}else{
for(b <- bytes){
flipByDoubleQuote(b)
keyword_buffer(keyword_count) = b
keyword_count += 1
}
isExist = true
}
//改行かファイルの終端の場合
//文字が1つも入っていない(空行とか、コメント行)場合はfalseを返す
if(isEndOfLine(ch) && isExist){
isExist = false
return true
}
return false
}

/**
* 1バイトのデータを追加しインクリメントする
*/
def addData(d:Byte):Unit = {
data(count) = d
count += 1
}

/**
* ダブルクォートと現在文字列内かどうかを判別し、isStringの値を変更
*/
def flipByDoubleQuote(d:Byte):Unit = {
if(d == KEY.DQUOTE && isString == false){
isString = true
}else if(d == KEY.DQUOTE && isString == true){
isString = false
}
}

/**
* Int型に直したデータを受け取り、4バイト配列としてデータに追加する
*/
def setNumber(num:Int):Unit = {
addData(((num >>> 24) & 0xFF).asInstanceOf[Byte])
addData(((num >>> 16) & 0xFF).asInstanceOf[Byte])
addData(((num >>> 8) & 0xFF).asInstanceOf[Byte])
addData(((num >>> 0) & 0xFF).asInstanceOf[Byte])
}

/**
* ファイル終端、もしくは改行を判別する
*/
def isEndOfLine(ch:Int):Boolean = {
if(ch == KEY.EOF || ch == KEY.NL){
return true
}
return false
}

/**
* ブロックの場合はtrueを返す
*/
def isBlock(b:Byte):Boolean = {
if(b == KEY.RBRACE || b == KEY.LBRACE || b == KEY.LPAREN || b == KEY.RBRACE || b == KEY.LBRACKET || b == KEY.RBRACKET){
return true
}
return false
}

/**
* 命令キーワードだった場合にはtrueを返す。
* データに、命令に対応する1バイトをセット
*/
def isOrder(key:String):Boolean = {
keyword_count += 1
key match {
case ORDER.DEF => addData(KEY.DEF)
case ORDER.IF => addData(KEY.IF)
case ORDER.SWITCH => addData(KEY.SWITCH)
case ORDER.WHILE => addData(KEY.WHILE)
case ORDER.FOR => addData(KEY.FOR)
case ORDER.PRINT => addData(KEY.PRINT)
case ORDER.INPUT => addData(KEY.INPUT)
case ORDER.PIXEL => addData(KEY.PIXEL)

case _ => {
keyword_count -= 1
return false
}
}
return true
}

/**
* 変数かどうかを判別
* ""で囲まれていない文字列は全て変数として扱う。
* ただし、name()のように、後方に括弧のある変数は、間数名として扱う
*/
def isVariable(b:Byte):Boolean = {
if((b >= KEY.VAR_BEGIN1 && b <= KEY.VAR_END1) || (b >= KEY.VAR_BEGIN2 && b <= KEY.VAR_END2)){
return true
}
return false
}

/**
* 数値かどうかを判別
*/
def isNumber(b:Byte):Boolean = {
if(b >= KEY.NUMBER_BEGIN && b <= KEY.NUMBER_END) return true
return false
}

/**
* 字句解析で分割する文字の場合はtrueを返す。
* ""で囲まれた文字列には、どんな文字が来たとしてもfalseを返す。
*/
def isSplitter(ch:Int):Boolean = {
if(ch == KEY.COMMA
|| ch == KEY.PLUS
|| ch == KEY.MINUS
|| ch == KEY.SLASH
|| ch == KEY.ASTERISK
|| ch == KEY.GT
|| ch == KEY.LT
|| ch == KEY.EQUAL
|| ch == KEY.LPAREN
|| ch == KEY.RPAREN
|| ch == KEY.LBRACE
|| ch == KEY.RBRACE
|| ch == KEY.LBRACKET
|| ch == KEY.RBRACKET
|| ch == KEY.NL
|| ch == -1){
if(!isString){
return true
}
}
return false
}


//範囲コメント時、アスタリスクがあった場合にその値を入れておく。
//次の値がスラッシュでなければ、この値は初期化される。
var comment_buff = 0
/**
* 行コメント、範囲コメントのモードを変更する
*/
def checkComment(ch:Int):Unit = {
if(ch < 0xFF){
if(ch == LINE_COMMENT){ //行コメント
comment_mode = LINE_COMMENT
}else if(ch == KEY.SLASH && comment_mode == 0){
comment_buff = KEY.SLASH
}else if(ch == KEY.ASTERISK && comment_mode == 0){ // /*の時
if(comment_buff == KEY.SLASH){
comment_mode = COMMENT_BEGIN
}
}else if(comment_mode == COMMENT_BEGIN){ // */の時
if(ch == KEY.ASTERISK){
comment_buff = KEY.ASTERISK
}else if(ch == KEY.SLASH && comment_buff == KEY.ASTERISK){
comment_buff = 0
comment_mode = COMMENT_END
}else{
comment_buff = 0
comment_mode = COMMENT_NONE
}
}else if(comment_buff == KEY.SLASH){
comment_buff = 0
}
}
}
}

2010.05.16[日] CとScalaとJNIと

メモ。
typedef struct SDL_Surface {
Uint32 flags; /* Read-only */
SDL_PixelFormat *format; /* Read-only */
int w, h; /* Read-only */
Uint16 pitch; /* Read-only */
void *pixels; /* Read-write */
SDL_Rect clip_rect; /* Read-only */
int refcount; /* Read-mostly */

/* This structure also contains private fields not shown here */
} SDL_Surface;


という構造体があったとき、これをScala側で扱うため、Scala側でクラスを作る。

class SDL_Surface {
flags:Int = 0
format:SDL_PixelFormat = null
w:Int = 0
h:Int = 0
pitch:Int = 0
pixels:Int = 0
clip_rect:SDL_Rect = null
refcount:Int = 0
}


Uint32はLongにしたほうが良いのかな。
でも値として使う直前に最上位ビットを使用しているかどうかを判別して意味のある値に変換してやれば問題ない?

javahを使ってheaderを作り、コードを書く。
以下のコードは、確認のために、flagsというメンバ変数に100という値を入れている。

  jclass surface = (*env)->FindClass(env, "SDL_Surface");
jmethodID cns = (*env)->GetMethodID(env,surface, "", "()V");
jfieldID fj = (*env)->GetFieldID(env, surface, "flags", "I");
jobject surface_obj = (*env)->NewObject(env, surface, cns);
jint rj = (jint)100;

(*env)->SetIntField(env, surface_obj, fj, rj);


手順
1.FindClassでScala側のクラスを取得し、jclass構造体変数を作成する。
2.GetMethodIDで、init、()Vを第3、第4引数に指定することで、コンストラクタメソッドを取得。
3.GetFieldIDで、クラスのflagsメンバ変数を取得。flagsはInt型なので、Iという文字を第4引数に与える。
4.NewObjectに、クラスとコンストラクタを与えて実体化。
5.SetIntFieldで、オブジェクトの、GetFieldIDで取得してきたメンバ変数と、そこにセットする値を指定する。

参考
http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/jniTOC.html

- 追記 -
オブジェクトをフィールドにセットするときは、"Lクラスの完全パッケージ名;"を型のところに記述する。

2010.05.14[金] objectが実際に生成されるのはー

JNIを使うときに、
object ObjTest {
System.loadLibrary("ObjTest")
}

class ObjTest {
@native def print():Unit
}

と書くと、loadLibraryが実行されないーと思ってて、色々右往左往。

val a = "hello"

とか書いたら、その時点でaに"hello"が束縛される=評価されている状態だと思い、

object ObjTest {
System.loadLibrary("ObjTest")
val a = "hello"
}


と書いた状態で実行してみたのですが、それでも無理。
で、printを呼び出す前に、aにアクセスするとOKだった。

ので、objectが作られるのは、中身を参照したときらしい?
プログラム実行時に同時に生成するようにするオプションとかあるのかな……。

2010.05.11[火] SCALAからCを呼ぶ

JNIをScalaで使うメモ。


SCALA_JNITest.scala
class SCALA_JNITest {
System.loadLibrary("SCALA_JNITest")
@native def printText():Unit
}

System.loadLibrary()を生成の度に呼んで良いものなのか気になる……。

Javaだと、
static {
System.loadLibrary("Hoge")
}

という感じに呼ぶみたいなので、同名のシングルトンオブジェクトを作って、そこでSystem.loadLibraryを行うようにしてみたら動作しませんでしたorz


$fsc SCALA_JNITest.scala

でコンパイルしたあと、

$javah -classpath .:/hoge/piyo/scala-library.jar SCALA_JNITest

とやって、C言語用のヘッダーファイルを作ります。
あとは、そのヘッダーファイルをインクルードして、Cのコードを書く。
#include <stdio.h>
#include "SCALA_JNITest.h"

JNIEXPORT void JNICALL Java_SCALA_1JNITest_printText(JNIEnv *env, jobject obj){
printf("Hello!");
return;
}


$gcc -shared -I/usr/lib/jvm/default-java/include SCALA_JNITest.c -o libSCALA_JNITest.so
でコンパイル。できた共有ライブラリを、Javaのクラスパスが通っている場所に設置する。

object CallJNI {
def main(args:Array[String]):Unit = {
val v = new SCALA_JNITest()
v.printText()
}
}

で呼び出せることを確認。

2010.05.10[月] public staticなメンバ変数にアクセスできない

ScalaでJavaのライブラリを使用していると、なぜか、そんな変数見つかんないよと怒られた。
javaでは実行できているので、scala側がまずいらしい?

ライブラリの名はJOGL2.0-BETA10。見つからないのは、GL2.GL_FLAT、GL2.GL_PROJECTION。

で、docを見ると、GL2.GL_FLATは、javax.media.opengl.fixedfunc.GLLightingFuncというインターフェースで定義されている。

public static final int GL_FLAT = 0x1D00;

↑こんな感じに。

javax.media.opengl.GL2インターフェースはGLLightingFuncを継承するので、アクセスできないとおかしい。それで、GL2.GL_FLATではなく、GLLightingFunc.GL_FLATにすると定義を見つけてくれた。インターフェースを継承するインターフェースからアクセスしようとすると見つからないみたい?

このあたりを上手く探してくれるようにする書き方とかあるのかな。


- 追記 -
http://cappuccino.jp/keisuken/logbook/20070824.html

にstaticメンバにアクセスできないことについての文章を発見。
staticメンバが定義されているクラスのサブクラスからはアクセスできないとのこと。

GLLightingFunc.GL_FLATという形で書きなさいーということ? かな……。


- 続・追記 -
ベータの文字が取れちゃってたりしてたりなんかしたら幸せだなーと思ってJOGLのサイトに行ってみたら、最新版はJOGL2.0 BETA10のままでした……。更新されないのかな。そろそろリリース版とか出ないのかな……。


全然関係ないんですが、ワッフルメーカーでホットケーキミックスの生地を焼いたものは、ホットケーキであってワッフルではないような気がするんです。
たこ焼き焼き機でホットケーキミックスの生地を焼いたものがたこ焼きにならないのと同じ理論です。きっとそれは鈴カステラに似た何かになるはず。

で、その理論を適用すると、学園祭で作ったワッフルは、ワッフルであってワッフルではなかったと。
それを私は、何食わぬ顔で、売っていたわけです。なんと罪深い。

また、あるとき私は、ホットケーキミックスで作るお菓子作りの本を入手しました。なんと、簡単に作れると書いてあるその文句に間違いはなく、パウンドケーキやら、スコーンやらが、簡単に出来てしまったのです。でも、それは、似非パウンドケーキであり、似非スコーンだったのかもしれないと。

そんな紛い物に騙された友人たちに、この場を借りてお詫び申し上げます。ごめんなさい。

でも、お好み焼き風たいやきが好きです。

2010.05.09[日] Liftを使う

Scala向けのウェブアプリケーション開発用フレームワーク?なLiftを試してみる。
GoogleAppEngineでも使えるようです。

Java1.5 JDKとMaven2が必要。

Apache Maven

Antに代わるJavaのプロジェクト管理ツール
http://maven.apache.org/
からダウンロードしてくる。

$tar xzvf apache-maven-2.2.1.tar.gz

.profileでPATH環境変数を設定
$vi ~/.profile
----------------------------------------------
$MAVEN_HOME=/home/username/apache-maven-2.2.1
export PATH=$MAVEN_HOME/bin:$PATH
----------------------------------------------



環境を適用
$source ~/.profile

$mvn
でPATHが通っているかを確認。

適当な開発用ディレクトリを作成し、その中で、

$mvn archetype:generate -U \
-DarchetypeGroupId=net.liftweb \
-DarchetypeArtifactId=lift-archetype-blank \
-DarchetypeVersion=1.0 \
-DremoteRepositories=http://scala-tools.org/repo-releases \
-DgroupId=argento.cuore \
-DartifactId=tarte \
-Dversion=1.0-SNAPSHOT

と言った形のQuickStartコマンドを実行する。
すると、必要なファイルが自動でダウンロードされる。

自動的にartifactIdの名前でディレクトリが作られるので、そこに移動し下記のコマンドを実行すると、Jettyサーバーが起動する。
$mvn jetty:run


つづく

Scala Feed

scala feed

FC2カウンター

プロフィール

RoNor

Author:RoNor
得意呪文はScalaですって言えるようになるのが夢です。
デスマーチ中、パーティメンバーの防御力を向上させたりさせなかったり。

検索フォーム

QRコード

QRコード

Copyright © 2009-2010 ARGENTO CUORE and RoNor All rights reserved.

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。