変奏現実

パソコンやMMORPGのことなどを思いつくまま・・・記載されている会社名・製品名・システム名などは、各社の商標、または登録商標です。

この画面は、簡易表示です

[c++]の配列

ネットで、

int a[3];
int j=1;
a[j] --> *(&a[0] + j) --> *(a + j) --> *(j + a) --> j[a]

と云うのを見つけた。

要点は四則演算の+演算子の前後は差し替えOKなので、

 *(a + j) === *(j + a)

であるとこで、C++ではポインタとintは同値扱いだから通る。(んだろうなぁ

実際、その通りだと思うけどね。

CPUのクロックが1MHzでメモリも数キロバイトな20世紀の頃ならともかく、

CPUのクロックが1GHz越えでメモリも数Gバイトな21世紀の昨今の視点で観ると

C++コンパイラが int j と宣言してるのにjの配列を認めない位のチェックはやっても良さげなので意外だった。

それでも、コンパイラがOKしてしまえば、C++のソースがアセンブラを通して機械語に変換されてしまえば・・・

多分、こんなアセンブラになって

データ・セグメント・レジスタ ds

データ・インデックス・レジスタ idx

データ・オフセット・レジスタ ofs

a[j] は、 Add ds, idx, ofs
j[a] は、 Add idx, ds, ofs は多分CPUの機械語には無いので、Add ds, idx, ofsに置き換えられるハズ

となり、どっちも同じに機械語に変換されるはずなので、(ま、いいか的にコンパイルも通すのかな?

a[j] = 4 とすれば・・・

同じ意味の機械語に翻訳されるj[a]も4になるのは当たり前。

不思議でも何でもない。

と思った。

しかし、WebAssemblyしか知らないと、Webで使う言語ではj[a]はエラってしまうと思うので

ソンナコードは通らない!

だから、C++が変!

と云うことになるのだろう。

そこにつっこみを入れるなら、

int a[3];
a[1000]=1;  // オーバーランしてるので、スタックのどこかが破壊される。

だって、コンパイルは通るだろうし、

関数のポインタだって何か変だなぁと思うトコはある。

そんなことよりも、ビット長が異なるCPUでも、異なるOSでも、同じソースが使え移植性の高いコンパイラというトコがずっと優先度が高い。

もしC++がなかったら、異なるOSやCPUで同じ言語を提供するには、全く別々のコードを書かなければいけないと思うが、今はWebAssemblyを使えば問題なし かもしれない。

でもそんなWebAssemblyはC++無しではリリースできない様な気がするので、

一般のプログラマはC++には手を出さない方がいい。

と思う。

そもそも、intとポインタが同一視されている理由は、OSやドライバ内部では、他人のモジュールが引き渡してくるポインタって実際にはアクセス不能だったり(CPUからGPUのメモリが見えるとは限らない等)するからintも同然なので、仕方が無いんだよなぁ。

CPU:ポインタって言ってますけど、それって貴方(GPU)の感想(アドレス)ですよね?

的な・・・(笑

手元のWindows上のArdunoの開発環境はx86-64系CPUで見知らぬCPUのコードをクロスコンパイルしてるのでArduno内部のアドレスもintもx86-64系CPUから見れば、どっちも只のint型データでしかない。

移植先のターゲットっていつも貧弱で自前ビルドなんて無理、高価な機械でクロスコンパイラするのが当たり前なC言語ができた頃の常識が今も残ってる。

そんな感じがした。



「家電」LEDシーリングライト代用リモコンOCR-LEDR3

アイリスオーヤマ LED シーリングライト 調光 調色 タイプ ~6畳 CL6DL-N1AZのリモコンが不調になったので、LEDシーリングライト代用リモコン OCR-LEDR3を買った。

DAISOの単4電池の形状のせいなのか?

リモコンと接触が悪く電池をしっかり抑えないとライトが付かなくなってきた。

シーリングライトのリモコンの型番がR5.0-DLからCL-RL2に変わったらしいけど、値が高め。

「cl-rl2 リモコン」でググり、Slanirishは送料無料の代用品(OCR-LEDR3)を見つけた!(即ポチっ

同じ型番のリモコンがOHM社から出ているけど、形状も違うし知らないブランドだった。

でも、多分使えるハズ。

もう一度、「cl-rl2 リモコン」でググると、Amazonにも送料無料の同等品(CLE9R9792T)が見つかった。

アイリスオオヤマ対応のリモコンは未対応のものとほぼ同型で違いはボタンが赤縁のデザインになっている。上の同等品の違いは「型番」だけ。

それにしても、検索結果の先頭のリモコンは形が同じでも説明文に「アイリスオーヤマ」がないリモコンだった(使えないじゃん)。

翌日ググってみると、どっちも検索結果に引っかかってない。(笑

(使えねぇw)AIっぽさが笑えるw

ps.2024/06/07

今朝届いた。

DAISOの電池ではホールド感が良すぎて、電池を外すのが大変なくらい。

アイリスオオヤマ用の設定値の数が多すぎて探すのが手間取ったけど、2221でOKらしい。

元々の灯モコンが1つのボタンで【入/常備灯/切】を切り替えるタイプなので、

【常備灯】【消灯】【全灯】が【入/常備灯/切】になってしまうがしょうがないか。

あと、電池を外した後も設定値を記憶していて再設定不要で使えるのは助かる。

これで、電池を抑えながら灯を付けたり消したりしなくてよくなったのはとても楽。

ps.2024/7/16

エアコンの汎用リモコンを買い増ししたら大失敗という記事を見つけた。

自室のエアコン未対応と云う結果だったらしいけど、汎用モノはエアコン購入の決め手になった「特長的な機能」が使えそうにない(そんなボタンは無い)ので、Wifi対応エアコンなら帰宅前に部屋を冷やせるメーカ製のスマホアプリの方がお勧め。但しアプリのセットアップ時にリモコンのボタン操作を要求されることもあるので、購入時にすぐにインストしないと後悔するし、アプリから全て制御できるわけでもない。



[Linux]cockpit が「保護されていない通信」扱い

httpsを使わないとChromeの機嫌が悪い。

でも、そのままhttpsにしておくと、「怪しい電子証明書」として扱われるので、

ブログのためにLet’s Encryptで取得した電子証明書を流用してみる。

Let’s Encryptでの電子証明書は、/etc/letsencrypt/live/の{コモンネーム}のフォルダの中の fullchain.pem(証明書)とprivkey.pem(秘密鍵)を使用する。

cockitでは電子証明書を、/etc/cockpit/ws-certs.d/ フォルダの中に格納することになっているので、先の証明書と秘密鍵のファイルを、{コモンネーム}.crtと{コモンネーム}.keyとしてシンボリックリンクを貼り、cockpitを再起動。

しかし、ブログのkvmホストは非公開だからChromeが安心する様な電子証明書は作りにくいので、ブログサーバのcockpitのホストリストにkvmホストを登録してソコから接続することにした。

ま、この方法だとブログのサーバを止める時に困るけどね。普段は使えるからヨシとしよう。



[三国英雄たちの夜明け]鯖統合その7

サーバー統合の告知がやっと来た。

また課金要素が増えるのかな?

近況

アップデートの日付はまだ未定。GW開けかな?

ps.2024/5/7 未だアップデート日付の告知無し

上位キャラの魂玉を強化したら戦力ダウン。

ps.2024/6/15

サーバ統合の案内がまだ来ない。

そして、公式HPが「メンテ中」のまま。

ps.2024/06/18

6/19に神霊のスキル調整が入る予定。

前回のサーバ統合では直前の4/21に調整が入り4/25に統合が来たから、今回も近々に統合くるかも(しれない

ps.2024/06/21

アップデート完了。

英雄のスキルの「専用チェックマーク」が消えていたので、全部付け直し

地味にメンドイ。

官邸の爵位に「未確認マーク」が出ていたのが気になって

念のため追っていくと・・・

『伯爵』で【神軍】と【龍行】が未解放!

解放したら異民族が出現する砦まで出向かなくても良いし、即終了するので手早くなった。

新規実装?見落し?(不明

次の爵位は「次国工」?達成条件は不明だけど、

貿易の速度や兵舎の保存上限が100%アップできそうだ。

官邸をレベルアップすると、領地レベル+1、英雄レベル+3にできるからこっちも大変そうだ。

とりあえずは、お米は大事に使わないとねぇ。

来週の火曜日あたりにサーバ統合くるかな?と書いたら、お知らせが飛んできた。

オンライン状態:14日前?までしかはランキングに載らなくなったから、

S6-1~4を一つに統合しても支障無いよね?

とか想像するだけでも、恐ろしぃ。



[javascript]spreadSheet4 コードのオブジェクト化

テキストを構文解析したパースした結果のオブジェクトはindexedDBに保存してあるけど、オブジェクトをテキストに戻したり、計算させるコードはJavaScriptのままだったので、中途半端だった。

あまり複雑なコトは出来なくていいので、オブジェクトをstringifyしたりcalulateしたりexecuteできるオブジェクトを考えてparserオブジェクトストアに保存すればいいかな?

そう考えると、まず俺々EBNFパーサで試してみるのが良さそうだ。

  • パースするEBNFなテキストを用意する
  • parserオブジェクトストアから俺々EBNFパーサを読みだす
  • パース部分とパース結果を手直す部分に分離
  • パース部分からdefinitionっぽいパーサ・コンビネーションを作る
  • パース結果を手直す部分から実行コードを作る
  • parseメソッドに先のテキストを読ませる
  • 何かの構文解析パーサができる

な感じだろうか

とりあえずはmakeParserメソッドを「パースした結果のオブジェクト」っぽいオブジェクトに展開。

するところから始め、stringify、calculateも「パースした結果のオブジェクト」っぽいオブジェクトに展開してみよう。

多分、

{ function_definiton: { name: x..., procedure:[.....] } }
{ return: {expr:... } }
{ if:{expr:... }, then:{...}, else:{...} }
{ while:{expr }, procedure:[.....]},
  {continue:null},
  {break:null},
{ function:{name:x..., parameter:{... } } }
{ expr:[x..., '+', x..., ...] }
{ value:{ type;integer, value:1 } }
{ set:{ name:x... }, value:{ expr or value:.... } }
{ try:[...], catch:[...], finally:[...] }

とかになるんだろう。+-と/*演算子の優先度は{}のネストでカバーすればいいし。

{ export: x..., from y... }
{ import: x..., from y... }

も必要か、javascriptのコードの呼び出しは、事前に「{function_definiton」の内部に登録しておこう。

execObjectList.map((execObject) => {
  switch() {
    case 'function_definition':
        {
        }
    ....
  }
});

と、実行用オブジェクトを種類別に仕分けてコード化すれば何とかなるだろう。



「javascript」spreadSheet4 EBNFの「,」

やっとマクロ構文を組み込み始めたが・・・

デリミタではまった。

(*$ imports: expression="EXPR" $*)
(*$ SEQUENCE SEPARATOR IS REQUIRED $*)
(* マクロ *)
macro               = { ( class declaration | function declaration | variable declaration ) }, /\s*/ ;
class declaration   = "class", class name, "{", { member declaration | method declaration } "}" ;
class name          = identifier ;
comment             = "/*", /.*/, "*/" | "//", /.*/, "\n" ;
member declaration  = [ "const" | "static" ], member name, [ "=", expression], { ",", member name, [ "=", expression] } ";" ;
member name         = identifier ;
method declaration  = [ ? ebnf reference jdoc.document ? ], [ method name ], parameter list, procedure list ;
method name         = identifier ;
function declaration= [ ? ebnf reference jdoc.document ? ], [ function name ], parameter list, procedure list ;
function name       = identifier ;
parameter list      = "(", [ parameter name, [ "=", expression ], { ",", parameter name, [ "=", expression ] } ], ")" ;
parameter name      = identifier ;
procedure list      = "{", procedure, "}";
procedure           =    {
                         (
                         | variable declaration 
                         | assignment expression
                         | branch procedure
                         | iterative procedure
                         | exception procedure
                         )
                      } ;
variable declaration= [ "const" | "let" | "static" ], variable name, [ "=", expression], { ",", variable name, [ "=", expression] } ";" ;
variable name       = identifier ;
assignment expression= variable name, [ ".", member name ] "=" expression;
branch procedure    = if procedure | switch procedure ;
if procedure        = "if", "(", expression, ")", procedure list, { "else", if procedure } ;
switch procedure    = "switch", "{", { case procedure } "}" ;
case procedure      = ( "case", expression | "default" ), ":", { procedure }, [ "break" ] ;
iterative procedure = for procedure | while procedure | do while procedure ;
for procedure       = "for", "(", assignment expression, ",",  expression  ",",  assignment expression ")" ;
while procedure     = "while", "(", expression ")", procedure list ;
do while procedure  = "do", "(", expression ")", procedure list, "while", "(", expression ")" ;
exception procedure = "try", procedure list, "catch", "(", parameter name ")", procedure list, [ "finally", procedure list ]
                    |  "throw", expression ;
identifier          = { comment }, /[A-Za-z][A-Z_a-z]/, { comment } ;

どこが間違っているのかな?

(*$ import expr from "EXPR" $*)
(*$ SEQUENCE SEPARATOR IS REQUIRED $*)
(* マクロ *)
macro               = { class declaration | function declaration | variable declaration }, /\s*/ ;
class declaration   = "class", class name, "{", member declaration, { method declaration }, "}" ;
class name          = identifier ;
comment             = "/*", /.*/, "*/" | "//", /.*/, "\n" ;
member declaration  = [ "const" | "static" ], member name, [ "=", expression], { ",", member name, [ "=", expression] }, ";" ;
member name         = identifier ;
method declaration  = [ ? ebnf reference jdoc.document ? ], [ method name ], parameter list, procedure list ;
method name         = identifier ;
function declaration= [ ? ebnf reference jdoc.document ? ], [ function name ], parameter list, procedure list ;
function name       = identifier ;
parameter list      = "(", [ parameter name, [ "=", expression ], { ",", parameter name, [ "=", expression ] } ], ")" ;
parameter name      = identifier ;
procedure list      = "{", procedure, "}";
procedure           =    { variable declaration 
                         | assignment expression
                         | branch procedure
                         | iterative procedure
                         | exception procedure
                         } ;
variable declaration= [ "const" | "let" | "static" ], variable name, [ "=", expression], { ",", variable name, [ "=", expression] }, ";" ;
variable name       = identifier ;
assignment expression= variable name, [ ".", member name ],"=", expression;
branch procedure    = if procedure | switch procedure ;
if procedure        = "if", "(", expression, ")", procedure list, { "else", if procedure } ;
switch procedure    = "switch", "{", { case procedure }, "}" ;
case procedure      = ( "case", expression | "default" ), ":", { procedure }, [ "break" ] ;
iterative procedure = for procedure | while procedure | do while procedure ;
for procedure       = "for", "(", assignment expression, ",", expression, ",", assignment expression, ")" ;
while procedure     = "while", "(", expression, ")", procedure list ;
do while procedure  = "do", "(", expression, ")", procedure list, "while", "(", expression, ")" ;
expression          = expr ;
exception procedure = "try", procedure list, "catch", "(", parameter name, ")", procedure list, [ "finally", procedure list ]
                    |  "throw", expression ;
identifier          = { comment }, /[A-Za-z][A-Z_a-z]/, { comment } ;

違いが判るだろうか?

最初は [ … […] … ] なんて囲み文字のネストは考えて無かったw!とか慌てたけど、そんなことを気にする様な気難しい文法解析方法は今回実装していない。

正解は・・・

  • importが旧仕様
    • ☓ imports: expression=“EXPR”
    • 〇 import expr from “EXPR”
  • sequenceのデリミタ(カンマ)がところどころ抜けている
    • 「}」の後
      • { … } , “;”
        • 「}」の後にトークンがあるなら、カンマで区切る必要がある
    • 「”}”」や「”)”」の前
      • { … } の } の前にカンマは不要、 ( … ) なら ) の前にカンマは不要
      • “{” … “}” の “}” の前にカンマは必須、 “(” … “)” なら “)” の前にカンマは必須

いづれも独自の仕様と云えば独自なのかもしれないけどね。

ps.import の処理が間違っていたので修正。EbnfParserクラスのparseメソッドを実行すると、export、importの情報が履歴の様に残っていたので、parseメソッド内でクリアするように変えるのでシャローコピーを各パーサに引き渡す様にした。

ps.2024/4/25

マクロファイルのアップロード、パーサ、indexedDB処理までできた。後はパーサのMap処理と実行部。どうすればいいのかは・・・やってみないと判らない。(笑



[javascript]spreadSheet4 クラス継承の見直し

  • CoreParsser
    • Parser
      • EbnfParser
        • CellValueParser
        • CellExprParser
        • ExportParser
        • ImportParser

とクラス継承をしているのに同じ名前のメソッドが内容は互いに独立しているため、ローカルメソッド名を使ってしのいでいたが、ほぼローカルメソッド名になってしまったので・・・・

CellValueParser以下は継承せず、フィールドにEbnfParserを保持し、

this._ebnfParser.parse('xxxxxxxxxxxxx')

のように変更した。

  • CellValueParser
  • CellExprParser
  • ExportParser
  • ImportParser
  • CoreParsser
    • Parser
      • EbnfParser

これにより、微妙だった初期化の手順が

  • SpreadSheetクラスで、EbnfParserクラスオブジェクトを生成しEbnfパーサを保持
    • EbnfParserクラスで、ExportParserとImportParserクラスオブジェクトを生成しExportとImportパーサを保持
  • SpreadSheetクラスで、CellValueParserクラスオブジェクトを生成しCellの値パーサを保持
  • SpreadSheetクラスで、CellExprParserクラスオブジェクトを生成しCellの数式パーサを保持

と安定してきたし、EBNFテキストでパーサを生成するクラスが全て独立したので、セルフテストの重複が減った。しかしsuper()でパーサを作るのが難しくなり、makeParserとselfTestに関連する処理をsetup()に纏める必要が出てきたついでにテンプレを作り、

/**
 *  EBNF関連のパーサのテンプレ
 */
class EbnfParserTemplate {
    /**
     *  パーサクラスオブジェクト
     * @memberof EbnfParserTemplate
     */
    _parser = null;
    /**
     *  自前のパーサ
     * @memberof EbnfParserTemplate
     */
    myParser = null;
    /**
     *  クラス名
     * @memberof EbnfParser
     */
    #className = 'EbnfParserTemplate';
    className = this.constructor.name;
    /**
     *  コンストラクタ
     */
    constructor() {
        //  パーサクラスオブジェクトを生成する
        this._parser = new Parser();
    }
    /**
     *  パーサ初期設定
     * @param {SelfTestInfo} fSelfTest 
     */
    setup(fSelfTest = false) {
        //  自前のパーサを生成する
        console.log(`${this.className}.constructor: makeParser().`);
        this.myParser = this.makeParser();
        //  セルフテストする
        if (fSelfTest) {
            const bk = this.DEBUG;
            this.DEBUG = fSelfTest;
            const selfTestRessult = this.selfTestList(this.getSelfTestList(), this.myParser);
            this.DEBUG = bk;
        }
    }
    /**
     *  パーサ生成 
     * @returns 
     */
    makeParser() {
        const myParser = undefined;
        return myParser;
    }
    /**
     *  EBNFルールと文法を作成
     * @param {string} ebnf             BNFテキスト
     * @param {Function} syntax         パーサ
     * @param {Function} evalProcInfo   パースした結果の評価関数情報
     * @returns {EbnfParseMethodResult} パース結果
     */
    parse(ebnfText, parser = this.myParser, evalProcInfo) {
        //  パース結果
        const parseResult = new EbnfParseMethodResult(/*success, result, position, result.result, definitionList, evalProcInfo*/);
        return parseResult;
    }
    /**
     * テスト処理
     * @param {Array of strung} testPatternList 
     * @param {function} parser
     * @returns {Array of ParseResult}
     */
    selfTestList(testPatternList, parser) {
        const methodName = 'selfTestList';
        const info = this.DEBUG;
        const parseResultList = testPatternList.map((test, index, a) => {
            if (info) {
                console.log(`${this.className}.${methodName}: pattern[${index + 1}/${a.length}]`);
            }
            return this.selfTest(test, parser);
        });
        return parseResultList;
    }
    /**
     * テスト処理
     * @param {string} testPattern 
     * @param {function} parser
     * @returns {Array of ParseResult}
     */
    selfTest(testPattern, parser) {
        const parseResult = this.parse(testPattern, parser);
        return parseResult;
    }
    /**
     * テストデータ取得
     * @returns {array of object}   テストデータリスト
     */
    getSelfTestList() {
        return [];
    }
}

全般的にExport、Import、Ebnf、セル値、セル数式のパーサクラスを見直したら、ゴチャゴチャしていたコンストラクタがすっきりした。

class  xxxParser extends EbnfParserTemplate{
    ・・・
    /**
     *  コンストラクタ
     * @param {EbnfParser} ebnfParser
     */
    constructor(ebnfParser) {
        super();
        this._ebnfParser = ebnfParser;
        this.setup(new SelfTestInfo(true, false, false, false));
    }
    ・・・
}

今現在のクラス継承はこんな感じ

  • CoreParser
    • Parser
  • EbnfParserTemplate
    • _parser <- new Parser()
    • EbnfParser
      • _parserList <- new ExportParser()、new ImportParser()
    • ExportParser
      • _ebnfParser <- コンストラクタのebnfParserパラメータ
    • ImportParser
      • _ebnfParser <- コンストラクタのebnfParserパラメータ
    • CellValueParser
      • _ebnfParser <- コンストラクタのebnfParserパラメータ
    • CellExprParser
      • _ebnfParser <- コンストラクタのebnfParserパラメータ



[javascript]spreadSheet4 repeateパーサの見直し

何故かEBNFのrepeateパーサだけ ‘{‘, sequence, ‘}’になっていて、気になっていた。

//  repeate     =   "{" sequence "}" ;
const repeate = _lazy(() => {
    return _map('repeate',
        '{', sequence, '}'
        , (parsed) => {
            parsed = this.arrayFlat([], parsed);
            const lparen = parsed[0];
            const seq = parsed[1];
            const rparen = parsed[2];
            let rc = seq['#sequence'];
            return { '#repeate0': rc };
        });
});

他に合わせて'{‘, choice, ‘}’にするとエラってしまう。

仕方が無いから、パースの動きをずーっと追っていくと・・・・・・・・・・・・・・・・・・・・・

灯台元暗しで、このパーサで、return { ‘#repeate0’: undefined }になっていた。

原因は、seq[‘#sequence‘];

choiceは、{#choice: xxxx}と返すので、当然の結果。

うっかりミスを減らす様に修正。

//  repeate     =   "{" choice "}" ;
const repeate = _lazy(() => {
    return _map('repeate',
        '{', choice, '}'
        , (parsed) => {
            parsed = this.arrayFlat([], parsed);
            const choiceResult = parsed[1];
            //  同じ繰り返しなら省略
            if (choiceResult['#repeate0']) {
                return choiceResult;
            }
            return { '#repeate0': choiceResult };
        });
});

やっとこれで、

{ ( A | B | C) }

の様に助長的な書き方をしなくても、

{ A | B | C }

で済むようになったし、

choice = sequence, { '|', sequence } ;

なので、{ … } の中は choiceでもsequenceでもOK。

しかし、

  • 数式のrepeate ※まだ未実装
  • ENBFのrepeate ※今回の主役
  • パーサ・クラスのrepeate ※今回の悪役
  • コア・クラスのrepeate ※今回はモブ

と、repeateが多くて紛らわしい。

ENBFのrepeateの文法は、'{‘, choice, ‘}’ になって便利になった。

しかし、パーサ・クラスのrepeateのパラメータは、ebnfParserのmakeParserメソッド中でmapメソッドのパラメータの文法部分をsequenceっぽく書きたいので、sequenceにまとめて処理している。目的が違うから仕様も違うんだけど、後で見返すとちんぷんかんぷんになってしまう。

動作確認をしているとパースの結果の内部構造が倍くらいに長くなっていたので短くした。

{
"syntax": {
  "#syntax": {
    "#rule_list": [
      {
        "rule_list": {
          "#definition": {
            "#repeate1": {
              "#choice": [
                { "#identifier": "rule" },
                { "#identifier": "special_effect" },
                { "#identifier": "comment" }
]}}}}]}}


[javascript]spreadsheet4 EBNF imports,exports

一度にマクロまで拡張すると修正が多そうなので、一旦、数式と値にEBNFを分割し、数式のEBNFから値のEBNFの(非)終端記号を参照できる様な仕組み(imports,exports)を作ってみた。

(*$ SEQUENCE SEPARATOR IS NOT REQUIRED $*)
(*$ export {value_cell,time_stamp,date,number,boolean,sqstring as singleQuoteString,text} from "CELL_VALUE"  $*)
(* セルのデータ *)
value_cell          = time_stamp | date | time | number | boolean | sqstring | text ;
time_stamp          = date ' ' time ;
date                = yyyy '/' MM '/' dd  | MM '/' dd ;
yyyy                = /\\d{4}/ ;
MM                  = /\\d{1,2}/ ;
dd                  = /\\d{1,2}/ ;
time                = HH ':' mm ':' ss | HH ':' mm  ;
HH                  = /\\d{1,2}/ ;
mm                  = /\\d{1,2}/ ;
ss                  = /\\d{1,2}/ ;
number              = /[-]?([0-9]+)([.][0-9]*)?/ ;
boolean             = /true/i | /false/i ;
sqstring            = /'.*/ ;
text                = /.+/ ;
(*$ SEQUENCE SEPARATOR IS NOT REQUIRED $*)
(*$ export expr from "EXPR" $*)
(*$ import defaultExport from "CELL_VALUE" $*)
(* セルのデータ *)
cell                = expr_cell | value_cell ;
(* 数式 *)
expr_cell           = '=' expr ;
expr                = logical_expr ;
logical_expr        = add_sub_expr [ ( '=' | '>' | '<' | '>=' | '<=' | '<>' ) add_sub_expr ] ;
add_sub_expr        = mul_div_expr { ( '+' | '-' | '&' ) mul_div_expr } ;
mul_div_expr        = factor { ( '*' | '/' ) factor } ;
factor              = value | parenthesis_expr ;
parenthesis_expr    = '(' expr ')' ;
value               = number | boolean | function_def | a1_range | a1 | dqstring ;
a1_range            = a1 ':' a1 ;
a1                  = /([A-Za-z]+[1-9][0-9]*)/ ;
dqstring            = /"[^"]*"/ ;
function_def        = symbol '(' parameters ')' ;
symbol              = /([A-Za-z][A-Za-z0-9_]*)/ ;
parameters          = [ expr ] { ',' expr } ;

node.jsのimportを参考にこんな感じになっている。

名前付き import: (*$ import { export1, export2 } from "module-name" $*)
デフォルトの import: (*$ import defaultExport from "module-name" $*)

こうすることで、

(*$ export {value_cell,time_stamp,date,number,boolean,sqstring as singleQuoteString,text} from "CELL_VALUE" $*)

値EBNF側で、{非}終端記号をindexedDBに書き込むtype名でexportする様にすれば、

(*$ import defaultExport from "CELL_VALUE" $*)

importする側はdefaultExportだけで済む。

テキストをガリガリしないでEBNFなimportParserとexportParserクラスを追加し、なんとか最低限の文法(上の2つダケ)を実装した。

(*$ SEQUENCE SEPARATOR IS NOT REQUIRED $*)
(* EXPORT *)
exportSyntax        = "export" members "from" ebnf_export_name;
members             = member | "{" member { "," member } "}" ;
member              = symbol { "as" alias } ;
alias               = symbol;
ebnf_export_name    = dqstring;
dqstring            = /"[^"]*"/ ;
symbol              = /([A-Za-z][A-Za-z0-9_]*)/ ;
(*$ SEQUENCE SEPARATOR IS NOT REQUIRED $*)
(* IMPORT *)
importSyntax        = "import" ( defaultExport | members ) "from" ebnf_export_name ;
defaultExport       = "defaultExport" ;
members             = member | "{" member { "," member } "}" ;
member              = symbol { "as" alias } ;
alias               = symbol;
ebnf_export_name    = dqstring;
dqstring            = /"[^"]*"/ ;
symbol              = /([A-Za-z][A-Za-z0-9_]*)/ ;

これらのEBNFをパースする時点ではまだimportもexportも未登録状態なので、各自がexport処理し、ebnfParserのparseの中で直接importとexportをimportさせた。

当初はebnfParser.#parse内でEBNFテキスト中のexportを処理させたが、cell_valueやcell_exprのパーサのマップを反映する前にimportしてしまったので計算するデータが全て文字になっていたから、各クラスで#makeParser後にebnfParser.exportメソッドを呼びださせた。

後、できるだけ、return [……] や {……} を、return new xxxx(….) に書換え。

なんでもEBNF化すれば良い訳ではないけれど、これに限ってはトコトンEBNF化しないと・・・



[javascript]spreadsheet4 special-effect (*$ … $*)

コメント(* … *)を独自に拡張し、(*$ … $*)の場合には特殊効果(Special Effect)を与えている。

意外と便利。

動作は、EBNFな文法テキストをEBNFパーサで解析する際には、

(*$ SEQUENCE SEPARATOR IS REQUIRED $*)           sequenceのパラメータは必ず[、]を使用する
(*$ SEQUENCE SEPARATOR IS NOT REQUIRED $*)       sequenceのパラメータは[  ]か[、]を使用する
(*$ DEBUG PRINT $*)  デバッグメッセージ用     EBNFテキストに差込みメッセージを表示させる

EBNFな文法テキストから作成したパーサで数式等を解析する際には、

(*$ NO SPACE SKIP $*) 字句判定前に空白をスキップしない
(*$ SPACE SKIP $*)  字句判定前に空白をスキップする
(*$ DEBUG PRINT $*)  デバッグメッセージ用 mapメソッドのsequenceパラメータ部に差込みメッセージを表示させる

とするつもりだったが、EBNFな文法テキストを読んでいる時に動作していたので、修正した。

Special-Text( ? … ? )として、他のEBNFテキストを参照する場合に ( ? jdoc ? :jdocを参照する)と云う感じにする予定。




top