プログラミング2(Kotlin+字句解析器)

勉強がてら2パターン試しました。
Tokenを返すメソッドの内容が少し違いますが、基本的な動作は一緒です。
Main.kt : メインループ
Token.kt : トークンタイプとリテラル(読み取った内容)のdata class
TokenType.kt : トークンタイプを示すenum class
Lexer.kt : 字句解析器(入力に対してTokenを返す)

forを使用した場合

Main.kt

fun main() {

    val input ="1+2*3/4-5"

    println(input)
    val l=Lexer(input)
    input.forEach {
        val tmp = l.nextToken()
        println("$it:${tmp.literal},${tmp.tokenType}")
    }
}

Token.kt

data class Token(val tokenType: TokenType, val literal: String)

TokenType.kt

enum class TokenType {
    ILLEGAL,
    EOF,

    INT, //整数

    //演算子
    PLUS, // +
    MINUS, // -
    ASTERISK, // *
    SLASH, // /
}

Lexer.kt

import kotlin.properties.Delegates

class Lexer(private val input: String) {

    private var position: Int = 0
    private var currentChar: Char by Delegates.notNull()
    private var nextChar: Char by Delegates.notNull()

    init {
        readChar()
    }

    private fun readChar() {
        currentChar = if (position >= input.length) {
            0.toChar()
        } else {
            input[position]
        }
        nextChar = if (position + 1 >= input.length) {
            0.toChar()
        } else {
            input[position + 1]
        }
        position++
    }


    private fun readNumber(): String {
        var number: String = currentChar.toString()
        while (isDigit(nextChar)) {
            number += nextChar
            readChar()
        }
        return number
    }

    private fun skipWhiteSpace() {
        while ((currentChar == ' ') || (currentChar == '\t') || (currentChar == '\r') || (currentChar == 'n')) {
            readChar()
        }
    }

    fun nextToken(): Token {
        skipWhiteSpace()
        var token: Token by Delegates.notNull()
        when (currentChar) {
            '+' -> {
                token = Token(TokenType.PLUS, currentChar.toString())
            }
            '-' -> {
                token = Token(TokenType.MINUS, currentChar.toString())
            }
            '*' -> {
                token = Token(TokenType.ASTERISK, currentChar.toString())
            }
            '/' -> {
                token = Token(TokenType.SLASH, currentChar.toString())
            }
            else -> {
                token = if (isDigit(currentChar)) {
                    val number = readNumber()
                    Token(TokenType.INT, number)
                } else {
                    Token(TokenType.ILLEGAL, currentChar.toString())
                }
            }
        }
        readChar()
        return token
    }

    private fun isDigit(c: Char): Boolean {
        return (c in '0'..'9')
    }
}

Iteratorを使用した場合

Main.kt

fun main() {
    val input = "+-*/===1234"
    val l = Lexer(input)
    val e = l.iterator()

    println("input : $input")
    while (e.hasNext()) {
        val tmp = e.next()
        println("TokenType: ${tmp.tokenType}, Literal: ${tmp.literal}")
    }
}

Token.kt

data class Token(val tokenType: TokenType, val literal: String)

TokenType.kt

enum class TokenType {
    ILLEGAL,
    EOF,

    INT, //整数

    //演算子
    PLUS, // +
    MINUS, // -
    ASTERISK, // *
    SLASH, // /
}

Lexer.kt

class Lexer(private val input: String) : Iterator<Token> {
    var position = 0

    override fun hasNext(): Boolean {
        return position < input.length
    }

    override fun next(): Token {
        val token: Token
        skipWhiteSpace()
        when (input[position]) {
            '+' -> {
                token = Token(TokenType.PLUS, input[position].toString())
            }
            '-' -> {
                token = Token(TokenType.MINUS, input[position].toString())
            }
            '*' -> {
                token = Token(TokenType.ASTERISK, input[position].toString())
            }
            '/' -> {
                token = Token(TokenType.SLASH, input[position].toString())
            }
            '=' -> {
                if (input[position + 1] == '=') {
                    token = Token(TokenType.EQ, "==")
                    position++
                } else {
                    token = Token(TokenType.ASSIGN, input[position].toString())
                }
            }
            else -> {
                token = if (readDigit(input[position])) {
                    val number = readNumber()
                    Token(TokenType.INT, number)
                } else {
                    Token(TokenType.ILLEGAL, input[position].toString())
                }
            }
        }
        position++
        return token
    }

    private fun readDigit(c: Char): Boolean {
        return (c in '0'..'9')
    }

    private fun readNumber(): String {
        var number: String = input[position].toString()
        if (lengthCheck()) return number
        while (readDigit(input[position + 1])) {
            number += input[position + 1]
            position++
            if (lengthCheck()) break
        }
        return number
    }

    private fun skipWhiteSpace(){
        while(input[position]== ' ' || input[position]=='\t' || input[position]=='\r' || input[position]=='\n')
            position++
    }

    private fun lengthCheck():Boolean{
        return position + 1 >= input.length
    }
}

入力と出力

input : +-*/= = =1234
TokenType: PLUS, Literal: +
TokenType: MINUS, Literal: -
TokenType: ASTERISK, Literal: *
TokenType: SLASH, Literal: /
TokenType: ASSIGN, Literal: =
TokenType: ASSIGN, Literal: =
TokenType: ASSIGN, Literal: =
TokenType: INT, Literal: 1234

一言

Iteratorを使うか使わないかの違い。
前回Iteratorパターンを勉強したので早速使ってみた。
字句解析器は先読みが重要みたいなので、前者のパターンの方が良いのかも。
事細かにtestをしてないのでバグありそう。

プログラミング1(Kotlin+Iteratorパターン)

Kotlin勉強中です。とても楽しい。
Iteratorパターン以降もアウトプットを兼ねて書いていきます。

抽象クラスと具象クラス

抽象クラス

・Aggregate → 集合体のinterface
Iterator → 集合体を数えるinterface

具象クラス

・Reagent → 試薬のIDと名前を表すdata class
・ReagentStorage → 試薬庫を示すclass
・ReagentStorageIterator → 試薬庫数えるclass
・Main → Mainclass

コード

Aggregate & Iterator

interface Aggregate{
	abstract fun iterator():Iterator
}

interface Iterator{
	abstract fun hasNext():Boolean
	abstract fun next():Any
}

Reagent

Javaと違ってデータを表すクラスを作成した場合にgetter/setterを書かなくて良いのが素晴らしい。

data class Reagent(val id:Int, val name:String)

ReagentStorage

class ReagentStorage(): Aggregate{

    private val reagents:MutableList<Reagent> by lazy{ mutableListOf() }
    
    private var last:Int = 0
    
    val getLength:Int get() = last
    
    fun getReagentAt(index:Int):Reagent = reagents[index]  
    
    fun appendReagent(reagent:Reagent){
        reagents.add(last,reagent)
        last++  
    }
    
    override fun iterator():Iterator = ReagentStorageIterator(this)
}

ReagentStorageIterator

class ReagentStorageIterator(val reagentstorage:ReagentStorage,private var index:Int = 0):Iterator{
    
    override fun hasNext():Boolean = index < reagentstorage.getLength
    
    override fun next():Any{
        val reagent:Reagent = reagentstorage.getReagentAt(index)
        index++
        return reagent
    }
}

Main

fun main(){
    val reagentstorae:ReagentStorage = ReagentStorage()
    
    reagentstorage.apply{
    	appendReagent(Reagent(1,"HCl"))
	appendReagent(Reagent(2,"H2SO4"))
    	appendReagent(Reagent(3,"HNO3")) 
    }
    
    val it:Iterator=reagentstorage.iterator()
    while(it.hasNext()){
        val reagent:Reagent = it.next() as Reagent
        println("ID:${reagent.id} Name:${reagent.name}")
    }
}

実行結果

ID:1 Name:HCl
ID:2 Name:H2SO4
ID:3 Name:HNO3
まとめ

setのようなコレクションで使うことを想定してるのかな。
参考文献では本↔本棚で書かれていたけど、似非化学系なので試薬↔試薬庫で書いてみた。

近況6

アコード ユーロR(LA-CL7)の整備について。

今回はディーラーでの整備が主です。

参考までに部品代、工賃を載せておく。

エンジンヘッドカバーからのオイル滲み

半年くらい前から気になっていたエンジンヘッドカバーからのオイル滲みをディーラにて整備。

ヘッドカバーパッキンの交換を行った。多分プラグホールパッキンも一緒に変わっている。

にじみとはいえ中々の期間放置していたのでゴム部品に油がベットリで萎えた。

f:id:blow000:20200807235411j:plain

エアーアシストバルブの破損

サクションパイプ側のホース接続部がちぎれていたため交換。ほぼほぼ部品代。もっと安いと思ってた。

交換前のエアーアシストバルブは、接着剤で修復した跡があったため、サクションパイプと繋がっているホースを取り外す際に破損したと予想。

前オーナーの残した整備記録からエアクリ周りを交換した記録があるためその時のやらかしかも。

f:id:blow000:20200807235151j:plain

 

次回

車遊びはしばらくお休み。

近況5

もうすぐ納車して1年になる車の不具合箇所を整備した。

アコード ユーロR(LA-CL7)の前期型。

 

手順等はサービスマニュアルを参照下さい。

 

最初に

自前で作業する際は、ネットで調べるなりディーラーに聞く等しっかり下調べした上で作業しよう。自分では出来ないと少しでも思ったらやらない方が良いです。クラッチ関係は動かないで終わるだけだけど(これも走ってる最中だと十分危ない)ブレーキ関係でミスったら最悪人生終わります。

自分もブレーキ関係(保安部品)はディーラーに任すことにしてます。

 

不具合箇所

クラッチマスターシリンダー

クラッチレリーズシリンダー

クラッチペダル

 

納車してから2、3ヶ月くらいでクラッチペダルを踏むたびにギコギコ音が鳴るようになった(アコードの持病らしい)。

音が鳴るのも大分不愉快だけどクラッチミートがまー分かりにくい。直すまで感覚でクラッチ操作をしていた。

 

ディーラーでエンジンオイルを交換するついでにギコギコ音について見てもらったところ、ペダルというよりマスターシリンダー或いはレリーズシリンダーから鳴ってるかも知れないと言われた(レリーズベアリングの可能性も有)。

ベアリングの方だったら悪化するまで放置するつもりだった(金欠)。

 

で、色々検討した結果、強化クラッチペダルを発見したのでマスターシリンダーとレリーズシリンダーと一緒に自前で交換することにした。

 

交換後

試乗してみてギコギコ音は無くなり、クラッチミートもはっきり分かるようになり最高の気分になった。

ただ、2速に入りづらいのは時たまある。これはマウント関係が原因っぽいのでクラッチ交換の折に変えてもらうと思う。

 

交換時の写真

f:id:blow000:20200531221359j:plain

クラッチマスターシリンダー

上部にタンクに繋がるホースとレリーズシリンダーに繋がる配管がある。

エンジンルーム作業ではここを外すだけ。

f:id:blow000:20200531221347j:plain

クラッチレリーズシリンダー

上部に2本あるボルトで固定されている。

また、マスターシリンダーからの配管がある。

左端にあるのがブリーダープラグ。ここにチューブを繋いでエア抜きをする。

緩める時は回しすぎない(1/3~1/2回転くらい)。逆に締めすぎにも注意。

f:id:blow000:20200531222021j:plain

左:交換前のクラッチペダル 右:交換後のクラッチペダル

交換前のペダルはサビがひどかった。
新品のペダルはJtcc Honda Kyotoさんから購入。

剛性感たっぷりで踏んでも歪み等は無し。

f:id:blow000:20200531222032j:plain

特にサビがひどい部分

サビ+歪み。

交換せずに使ってたら割れて終了した思う。

 

まとめ

交換作業自体は下調べを根気よく行ったので比較的順調に行えたと思う。大変だったのはマスターシリンダーのフランジナットの取り外し・取り付けくらい。

作業と共に何故かクラッチスタートシステムのスイッチが終わったのでハーネスを適当に作って直結した。あっても無くても正直変わらないので多分そのまま。

 

次は、インマニ計取り付けかシフトポジションインジケーター自作をする予定。

ただ、ヘッドカバーの隙間からオイル漏れ疑惑があるのでそっちの対処が先かもしれない。

ジャッキアップ出来ない環境なのでディーラーに任せる感じ。悲しい。

 

 

部品番号

クラッチマスターシリンダー:46920-S7A-A05

クラッチレリーズシリンダー:46930-S7C-E02

 

近況4

空気を十分に入れずにママチャリに乗っていたら後輪がパンクしたので修理した(チャリ屋が遠くて車にも載せられず自分でやる感じに)。

チューブのどこに穴が空いているのか調べるのが面倒臭かったので、チューブ自体を交換。

f:id:blow000:20200307190219j:plain
 

ブレーキワイヤーと後輪の取り外し

後輪を外す前にブレーキワイヤーを外した。

調整ナットがついている部分と、ブレーキワイヤーが固定されているナットの二箇所。

f:id:blow000:20200307190536j:plain

 外すとこんな感じ。

f:id:blow000:20200307190627j:plain

 

後輪の取り外し

両側についているハブナットを緩めて泥よけやスタンドを固定しているバーを取り外す。

外せたらチェーンを外側に寄せつつ、後輪を外す(必死だったので写真を撮り忘れた)。

f:id:blow000:20200307190756j:plain
後輪を外すときは台があると良いけど無かったので逆さにした。

ベルがハンドルの下敷きになるので予め外しておく。

また、気になるならハンドル側にキムタオル等のウエスを敷いておけば良いと思う。

 

タイヤの取り外しとチューブ交換

 タイヤを外すときはタイヤレバーなるものを使うと良いらしいけど持っていなかったので車用の内張り剥がしで代用した。

外し方は、1本目の内張り剥がしをタイヤの内側に挿し込んでぐいっと捻って外側に追いやりつつ、もう2本目の内張り剥がしで少し離れたとこを外側に追いやる感じ。

数回繰り返して剥がしたのが以下(サビがすごい)。

f:id:blow000:20200307190913j:plain

剥がした後は、穴が空いたチューブを外しつつホイールに付いているブチルゴムに異常が無いか確認した。

f:id:blow000:20200307151125j:plain

新しいチューブは、ホイール側ではなくタイヤ側にムラがないように挿し込んでいく。

タイヤを戻すときは、空気を入れる部分を確認しながら戻していく。

その後は逆の手順で後輪を戻して終了。お疲れさまでした。

 

まとめ

後輪の脱着とチューブ交換合わせて1時間位かかった。

車いじりに比べて作業性が抜群に良いので割とすんなりいった。

だが、ブレーキワイヤーの調整に少し手間取った。まだ遊びが多少多いので乗りつつ調整する。

 

動力の付いて無い物に興味が無いのでメンテを怠っていたが、通勤の足なので今後はメンテを怠らないようにしたい。

 

車の方も色々配線をいじった結果足元が凄まじいことになっているので、整理する予定。

インマニ計とか水温計もつけたい(i-VTECなので水温はすごい気になる)。

 

次回は、車の紹介か電子工作の続き。

 

近況3

初めて自作PCやってみました。流行りのRyzenを使ってみたかった。IntelのCPU以外が載ってるパソコンは多分初めて。

 

構成は以下。

CPU AMD Ryzen 5 3500

MB ASRock B450M Steel Legend

Memory Patriot Viper Steel 8GB(DDR4-3200) ✕ 2

Storage Crucial CT500MX500SSD1/JP

GPU ASRock Radeon RX5500XT Challenger D 8GB(GDDR6) OC

Supply 玄人志向 KRPW-AK650W/88+

Chassis Thermaltake Versa H17

その他 シャーシ用のファン、OS(Win10),モニター(24inch),キーボード、マウス

 

その他を除いて79,330円(含めると108,014円)。

 

FF15ベンチマーク(標準1920)は8000後半くらい。

CINEBENCHは、2562と466(Single Core)。

メモリはXMP2.0?を適用してて3200MHzで駆動してると思う(正直良くわかっていない)。

 

Far Cry5とかトゥームレイダーとか早速プレイしてるけど、設定を何もいじらずにヌルヌル動く。カクツキ等は無し。

パーツだけで100k行ってないのにこれは上出来だと自画自賛してみる。

 

失敗点

グリスをどれだけ塗ればよいのか分からず、塗りすぎて横から漏れ出した。

焦ってCPUクーラを取り外したときにMB上のピンソケット、基盤にグリスが付着した。

CPU本体のピン側にも何故か付着していた(グリスがついた手で触ったためだと思う)。

 

どうしたもんか少し考えて、エレクトロニッククリーナーというものがあると知り、ホームセンターで購入。

意を決してグリスが付着した部分に吹いた結果キレイにグリスを流し落とせた。

すぐに揮発してグリスがMB上に残ってしまったので、上からウエスを被せて再度吹きウエス上に汚れを吸わせた。

吹いた後は、一晩放置で朝っぱらからPC組んだ。

 

まとめ

いつも1から電子回路とか設計したり色々自作しているし、自作PCくらい余裕やろと思ってたが、部品選定(結果的に見た目重視だった)とか配線取り回しとか案外奥深かった。

初心者がやらかしそうなミスも一通りやったのでそれらを糧に次の自作PCはもう少しハイエンド気味でやってみたい。

乗り物シミュレーターマシンとか面白そう(G27とか飛行機用のコントローラーとか使うやつ)。