2024年11月5日火曜日

XML 構造のファイルシステムへのシリアライズ化及びFUSEの導入について

またまたChatGPTに聞きながらアイデアをまとめていた。

お題は例の「XMLのファイルシステムへのシリアライズ」及び「FUSEの導入に関する考察」と言ったところだろうか

まず以下の質問を投げた

XMLを以下のようにファイルやフォルダ構造に変換しようと考えた

XML例

<books>
    <author name="太宰治">
太宰の作品
        <book title="人間失格" price="100">
         <book title="走れメロス" price="90">
    </author>
    <author name="尾崎紅葉">
        <book title="金色夜叉" price="200">
    </author>
</books>

これを以下フォルダ構造にする
root/0_books/0_author/inner.txt(content:name=太宰の作品)
root/0_books/0_author/attr.txt(content:name=太宰治)
root/0_books/0_author/0_book/attr.txt(content:title=人間失格<crlf>price=100)
root/0_books/0_author/1_book/attr.txt(content:title=走れメロス<crlf>price=90)
root/0_books/1_author/attr.txt(content:name=尾崎紅葉)
root/0_books/1_author/
0_book/attr.txt(content:title=金色夜叉<crlf>price=200)

これであれば、元のxmlを完全にフォルダ構造から復元できる

その上で、FUSEを使えば上記のファイルやフォルダのattr.txtをファイルやフォルダのプロパティとして扱える上に、同一ファイル名や同一フォルダ名の順序も、プロパティの一部として扱えるようになると考えた

以下ChatGPTの答えとなる

このアイデアはとても理にかなっています。FUSEを使うことで、次のようなことが実現可能になります。

1. 属性情報のプロパティ化: attr.txtの内容をファイルやフォルダのプロパティとして扱うため、FUSE層でファイルやディレクトリのメタデータにこれを反映できます。例えば、ファイル操作時に「プロパティ」としてXMLの属性情報が直接利用者に提供されるように見せることができます。
2. 順序の保持: XMLの構造上、同じタグ名で複数のノードが並んでいる場合、その順序が重要です。これも、ディレクトリ名に一意の番号をつけることで保持され、復元時に元の順序が維持されます。
3. XMLの復元: フォルダ構造に従ってファイルを解析することで、元のXML構造に再構築するのが容易になります。特にinner.txtやattr.txtに保存された内容を解析すれば、元の階層構造やテキスト内容、属性も再現できます。
4. 可視性と柔軟性: 利用者にはファイルシステムとして見えるため、XMLの要素を操作する際に通常のファイルシステム操作と同じ感覚で利用でき、複雑なXMLデータの管理が直感的になります。

実装のポイントとしては、FUSEでopenやreadといった各種操作をカスタマイズし、attr.txtの内容をファイルやフォルダのメタデータに割り当てることが重要です。このようなファイルシステムなら、XMLの複雑な構造もフォルダベースで整理され、柔軟な操作が可能になるでしょう。


つまり大当たりなのではないだろうか?
これはやるしかないなぁ

2024年10月20日日曜日

Nuxt + PrimeVue をお試し中

Windows環境にあれこれ設定するのも嫌・・・

というかそもそもWindowsで開発するのが嫌なので、

うちに常時稼働しているRaspberryPiで開発することにする。

(別にWSLでもいいんだけど)

うちのRaspberryPiにはUbuntuが入っているので、VSCodeからリモートでつないでターミナルを起動


■全部すっ飛ばしてNuxtを使ってみる

まずはnpmを入れる

sudo apt install npm

終わったら次はプロジェクトを作成するので、適当なフォルダをつくる

mkdir nuxt_test

cd nuxt_test

続いて、プロジェクトを作成する

npx nuxi@latest init timer

プロジェクト名はtimerにしてみた

(タイマーを設定して動かすだけのページでも作ろうかと思ってみた)

しばらくするとプロジェクトができるので、ターミナルから起動してみる

npm run dev -- -o

しばらく待つと、http://localhost:3000で起動される

ラズパイのIPじゃなくてlocalhostなんだけど、なぜか動く(なんで?)


nuxtのGetting Startedのページを読み進めると、Nuxtのフォルダ構造が出てきた

pagesフォルダを作るのがいいらしい

timer/pages/index.vueを作る

中身はコレ

<template>
  <h1>Index page</h1>
</template>


つづいて、pagesを使う時にはapp.vueを書き換えるらしい

timer/app.vueはすでに存在しているので、中身を変える

<template>
  <div>
    <!-- Markup shared across all pages, ex: NavBar -->
    <NuxtPage />
  </div>
</template>

NuxtPageはpagesフォルダを使う設定らしい

これによって、pages/index.vueがhtmlとして解釈されて表示されるようになる。

ブラウザでIndex pageと表示されていればオッケー

続いて、今動いているターミナルを一度Ctrl+Cで止め、primeVueを入れる

npm install primevue

npm install --save-dev @primevue/nuxt-module

primeVueのテーマを入れる

npm install @primevue/themes

アイコンも入れとく

npm install primeicons


つづいて、nuxt.config.tsを編集

// https://nuxt.com/docs/api/configuration/nuxt-config
import Aura from '@primevue/themes/aura';
export default defineNuxtConfig({
  compatibilityDate: '2024-04-03',
  devtools: { enabled: true },
  modules: [
    '@primevue/nuxt-module'
  ],
  primevue: {
    options: {
      ripple: true,
      inputVariant: 'filled',
      theme: {
        preset: Aura,
        options: {
          prefix: 'p',
          darkModeSelector: 'system',
          cssLayer: false
        }
      }
    }
  }
})

ついでにpages/index.vueへボタンを追加してみる

<template>
  <h1>Index page</h1>
  <Button label="Check" icon="pi pi-check" />
</template>


ターミナルからnpm run devsして、

こんな感じで表示されればオッケー

ん?なんかCheckボタン形偏ってない?わざと?



まぁ気を取り直して

pages/index.vueを編集

IftaLabelというのを使ってみる

<script lang="ts">
import IftaLabel from 'primevue/iftalabel';
</script>


<template>
  <h1>Index page</h1>
  <Button label="Check" icon="pi pi-check" />
  <IftaLabel>
    <InputText id="username" v-model="value" />
    <label for="username">Username</label>
  </IftaLabel>
</template>


動かしっぱなしでもホットスワップ?
ページが変わってくれるのは便利


にしてもこの緑、気に入らない・・・
なんとかならんのかと説明を読んでいたら、Noirモードの定義をしているところがあった。
テーマのAuraをベースにして、あれこれカスタマイズしてNoirを設定している
nuxt.config.tsに結構書き込むことになるけどこんな感じ

// https://nuxt.com/docs/api/configuration/nuxt-config
import PrimeVue from 'primevue/config';
import { definePreset } from '@primevue/themes';
import Aura from '@primevue/themes/aura';

const Noir = definePreset(Aura, {
  semantic: {
      primary: {
          50: '{zinc.50}',
          100: '{zinc.100}',
          200: '{zinc.200}',
          300: '{zinc.300}',
          400: '{zinc.400}',
          500: '{zinc.500}',
          600: '{zinc.600}',
          700: '{zinc.700}',
          800: '{zinc.800}',
          900: '{zinc.900}',
          950: '{zinc.950}'
      },
      colorScheme: {
          light: {
              primary: {
                  color: '{zinc.950}',
                  inverseColor: '#ffffff',
                  hoverColor: '{zinc.900}',
                  activeColor: '{zinc.800}'
              },
              highlight: {
                  background: '{zinc.950}',
                  focusBackground: '{zinc.700}',
                  color: '#ffffff',
                  focusColor: '#ffffff'
              }
          },
          dark: {
              primary: {
                  color: '{zinc.50}',
                  inverseColor: '{zinc.950}',
                  hoverColor: '{zinc.100}',
                  activeColor: '{zinc.200}'
              },
              highlight: {
                  background: 'rgba(250, 250, 250, .16)',
                  focusBackground: 'rgba(250, 250, 250, .24)',
                  color: 'rgba(255,255,255,.87)',
                  focusColor: 'rgba(255,255,255,.87)'
              }
          }
      }
  }
});

export default defineNuxtConfig({
  compatibilityDate: '2024-04-03',
  devtools: { enabled: true },
  modules: [
    '@primevue/nuxt-module'
  ],
  primevue: {
    autoImport: true,
    options: {
      ripple: true,
      inputVariant: 'filled',
      theme: {
        preset: Noir,
        options: {
          darkModeSelector: false,
        }
      },
    }
  }
})



ついでに、アイコンも試そう

pages/index.vueを以下のように編集
<script setup lang="ts">
import Button from 'primevue/button';
import IftaLabel from 'primevue/iftalabel';
import 'primeicons/primeicons.css'
var value = "aiueo";
</script>


<template>
  <h1>Index page</h1>
  <Button label="Check" icon="pi pi-check" />
  <div class="card flex flex-col items-center gap-4">
    <div class="flex flex-wrap gap-4 justify-center">
      <Button icon="pi pi-home" aria-label="Save" />
      <Button label="Profile" icon="pi pi-user" />
      <Button label="Save" icon="pi pi-check" iconPos="right" />
    </div>
    <div class="flex flex-wrap gap-4 justify-center">
      <Button label="Search" icon="pi pi-search" iconPos="top" />
      <Button label="Update" icon="pi pi-refresh" iconPos="bottom" />
    </div>
  </div>
  <IftaLabel>
    <InputText id="username" v-model="value" />
    <label for="username">Username</label>
  </IftaLabel>
</template>

こんな感じの表示になる
あーそうか、Checkの左にチェックマークがあったから偏ってたのか・・・


アイコンも出たし、ようやくまともになってきた。
わたしがPrimeVueすごいなと思ったのは、カレンダーとか補完テキストボックスとか、
自分で作るのがめちゃくちゃ嫌なパーツがそろっていた点

■ちょっと落ち着いてどうなってるのか考察

そもそもVueとはJavaSctiptのフレームワークで、UIを構築できる。
UIはどうもブラウザUIだけではないらしい。

では、vueのアプリを作ってみる
mkdir ~/vue_test
cd vue_test
npm create vue@latest

途中プロジェクト名を聞かれるので、firstProjと入力しあとはただエンターを押した
cd firstProj

vscodeでfirstProjを開いてみた
ターミナルを開いて
npm install
npm run dev

ターミナルにlocalhost:xxxxと出るので、Ctrl+クリックで開くとページが表示される


次にターミナルからCtrl+cで止め、
npm run build

distフォルダにあれこれファイルが出来上がる
これを適当なWEBサーバにおいてあげればきっと動くのだろう
こうしてみるとNuxtの説明とあまり変わらないのだけど
さきほどの画面を見ると、vite+vue3と書かれている
どうやらviteというのがimport なんたら from なんたらという書き方をしているもので、
viteの作者とvueの作者は同じ人であり、viteはvueのビルドツール?という位置づけらしい
本気でわからなくなってきた

出来上がったものだけで判断すると・・・
nuxtはサーバサイドも開発できるもので、サーバはNitroを使っているという。
根っこはvueで、さらにビルドツールとしてviteがあるって感じなのだろうか
しかし、実際のビルドはnpmでやってるわけで・・・
npmの作者はたしか、npmの爆発問題を何とかするためにGoでdenoを作っていて、
途中からRustに移行してるんじゃなかったか?

コンポーネントベースで開発するというやり方を勉強するには、
まずはvueを勉強した方がよさそうなのだけど、
Nuxtでも結局同じようにコンポーネント単位で機能を実装していくことになるため、
vueのテストはここまでにして、
このままNuxtでコンポーネントの作り方を調査することとする。

■JSONのキーとバリュー再帰的にIftaLabelで表示したい

ではIftaLabelを簡単に表示するコンポーネントを作る
components/dispjs.vueを作成する
中身は
<template>
    <IftaLabel>
        <InputText id={{keyStr}} v-model=valStr readOnly=true />
        <label for={{keyStr}}>{{ keyStr }}</label>
    </IftaLabel>
</template>

<script setup>
const keyStr = defineModel('keyStr')
const valStr = defineModel('valStr')
</script>


続いて、index.vueにJSON入れたりあれこれしてdispjsを呼び出す

<script setup lang="ts">
import Button from 'primevue/button';
import IftaLabel from 'primevue/iftalabel';
import 'primeicons/primeicons.css'
import dispjs from '~/components/dispjs.vue';

const contentJSON = {
  Subject: "件名",
  date: "2024-10-19",
  entry: [
    { resource: { resourceType: "目次" } },
    { resource: { resourceType: "はじめに" }, display: "本書を書くにあたり、多くの方にご助力いただきました事を感謝します。", author: ["Aさん", "Bさん", "Cさん"] },
    { resource: { resourceType: "一章" }, display: "まずは動かしてみましょう。" },
    { resource: { resourceType: "二章" }, display: "つぎは応用してみましょう。" },
    { resource: { resourceType: "あとがき" }, display: "最後までお読みいただきありがとうございます。" },
  ]
}

// function dispRecurse(d: any) {
//   if (typeof d === 'object' && d !== null) {
//     for (const key in d) {
//       if (d.hasOwnProperty(key)) {
//         console.log(`${key}:`)
//         dispRecurse(d[key]);
//       }
//     }
//   } else {
//     console.log(`${d}`)
//   }
// }
// dispRecurse(contentJSON);
</script>


<template>
  <h1>Index page</h1>
  <div v-for="(val, key) in contentJSON">
    <dispjs :keyStr="key" :valStr="val" />
  </div>
</template>

ちょっとJavaScriptでどうなるのか試したコードがあるけどコメントアウトしとく・・・
v-forでやってるんで再帰できてない・・・
画面表示はこんな感じ

entryの中は配列で入っているので、上のソースの再帰処理できちんと出せるんだけど、
これをコンポーネント化する方法がまだよくわかってない。
dispjsはラベルとインプットを一緒くたにしたIftaLabelというものを使って表示している。
この際、引数ですごく悩んだ。
export propsとかinterfaceとかやったけど、InputTextでv-model使っててうまくいかなかった。
そこでコンポーネントでもv-modelで引数を設定してやると、
双方向でバインドできるらしく、
Vue3.4以降はdefineModelを使うと楽よ?という情報は手に入ったのでやってみたらうまくいった。

■まとめ
正直全然わかってない・・・
コンポーネントとの引数のやりとりは、v-modelでひと段落したということになるのだろうか?それともまだまだ変わるのだろうか?

Componentで関数書いて再帰処理とかのやり方もまだわからない。

いや、分かった
しかし、よく考えたらそんなことせずとも
scriptで再帰してデータをフラット化して
DataTableやv-forで表示した方がVueとしては正当なやり方だと考えついた。
ので、再帰はできるけど敢えてやらない

2024年9月30日月曜日

MakoServerを動かしてみた

MakoServerというものがある

Lua ServerPage(LSP)を処理するWEBサーバという位置づけで、LSPという拡張子のファイルをHTMLとして表示してくれる
LSPの中にはLuaScriptを書くことができる
ログインフォームのサンプルを表示してみた

これをIISなどで表示するのであれば、
IISからMakoServerへポートフォワードしてやればよさそう
Luaは型の無いスクリプト言語で最速といわれている

GitのサンプルにはWebSocketなどもあり
コンパイル無し(内部ではやってるようだけど)で動かせるため開発効率も高いはず



2024年9月27日金曜日

HTML+JavaScriptで封筒宛名印刷

封筒の宛名印刷をしようと思いHTML+JavaScriptで作ってみました

サンプルをこちらに置きます

ダウンロードして開くとこのようなページが表示されます



キーボードのnでNext、pでPrevious、rで180度回転します


うちのHP SmartTank 6006では回転印刷ができないので、

rを押してひっくり返った状態で印刷をします

ブラウザからプリントで封筒へ印刷できます


封筒は前面給紙トレイに、封筒の表面を下+封筒の閉じる側を手前に向けてセット

位置がずれる場合は適宜調整をお願いします(HTML内に座標が書いてあります)

データはHTML内にJSONで定義されているので、それを参考に差し替えてください




2024年9月25日水曜日

DBでMAX

 DBでIDなんてものはオートインクリメントにしておけよと思うのだけど

select
    max(id)
from
    TBL_A;


こういうのでIDのMAXを取得してインクリメントしてインサートというパターンがある

ところで、上記SQLには大問題がある

データが入ってない場合、NULLになってしまうのだ

するとMAX取得ができないでエラーとなる

仕方ないのでこうする

select
    COALESCE(MAX(id),-1)
from
    TBL_A;

これだと一件もデータがないときには-1となり、インクリメントして0

そのままインサートしてIDが0のデータが出来上がる

次からはMAXを取得するので0が取得できるため、インクリメントして1

そのままインサートしてIDが1のデータが出来上がる


元からダミーデータが入っているような環境だと気が付かないので要注意だ

ついでに書いておくけど

DBにテーブルを作るとPrimaryKeyが必要になる

これが何のために使われるかというと2点あって

1.重複しないため

2.ソートのため

ここで2はあまり重要ではない

IDでソートするパターンなんてあまりないからだ

なので重複しない目的のためならUDIDのようなものを割り振っても構わないはずだ

しかし、本当にそうか?

実はDBのPrimaryKeyとは、インデックスがあるため、順番を検索してインサートが行われる

すると、UDIDの山を一生懸命探しに行くことになるのでインサートは遅くなる


ちなみに大手のDBでは、インデックスを3つ作成するとインサートが10倍遅くなると言う


わたしはこの点、もはやDBの構造的問題に思えて仕方ない

ここ数年かけてXML DBについて考えてきたが

XML DBであればこういうソートだのインデックスだのいう概念をうまく包括できると考えている(インデックスが自動的に勝手に存在するようになる)

その果てにたどり着いたのはファイルシステムで表現してしまえばいいではないかという結論だった(様々な考察をして利点があると考えた)

しかし、次にファイルシステムでは足りないということにも気が付いた

そこで既存ファイルシステムでは何が嫌なのかという点を列挙してみることにした


1. 同じフォルダに同名のファイルやフォルダが作れない

2.ファイルやフォルダに任意のプロパティを設定できない

3.ファイルやフォルダの順序が明確ではない

4.パスに限界がある


何言ってるかわからないかも知れないが

わたしは非常識な事を言っているのである

逆に言うと常識で考えないでほしい


WindowsでもLinuxでもファイルシステムはかなり昔からあるものを拡張し続けている

しかし、上記4点を改善できれば、XMLのタグやInnerTextなどをそのままファイルシステムで表現できるようになる

もちろん、JSONやYAMLもファイルシステムに置き換えられるだろう


早速ファイルシステムを考え始めた(いまさらか?)

世の中にはFUSEというものがある

これを使うと結構簡単に実現できるかもしれない

あとは設計製造だ

今ここまでたどり着いた

2024年8月25日日曜日

3Dプリンタを園芸へ

 最近3Dプリンタを園芸に使っている

バラ用の鉢はこれに統一することにした


PETGで作れば耐候性も充分だ

サボテンの方は以前投稿した通り

TPUで六角形の小さい鉢を作り沢山植えてある

2024年8月11日日曜日

XML Dataをフォルダやファイルシステムでシリアライズする方法に関して考察

XML Databaseライクなものを作るために、XML構造をフォルダとファイルにシリアライズする方法をずっと模索してきた

大体アイデアが固まったので、ChatGPTに聞いてみた

そしたらPythonコードで確認までしてくれて、おいおいお前まぢかってなった

ただし、わたしは知っている
途中に挿入するコメントの事を考えてない(コメントは無視で保存したいが、、、)

ネームスペースはフォルダにアンダーバーで区切って保存するように考えている

====ChatGPTに聞いた内容

XMLをフォルダやファイル構造にしてシリアライズするアイデアを再考していたが
アトリビユートをファイル名にすると、元のXMLを再現する事ができない(アトリビユートの順番が再現不能)

そこでアトリビュートをAttr.txtにまとめ、タグ内のテキストはinner.txtに保存するように考えた

タグはフォルダにするが、プレフィックスとして番号付けを行う

<books>
    <author name="太宰治">
太宰の作品
        <book title="人間失格" price="100">
         <book title="走れメロス" price="90">
    </author>
    <author name="尾崎紅葉">
        <book title="金色夜叉" price="200">
    </author>
</books>

これを以下フォルダ構造にする
root/0_books/0_author/inner.txt(content:name=太宰の作品)
root/0_books/0_author/attr.txt(content:name=太宰治)
root/0_books/0_author/0_book/attr.txt(content:title=人間失格<crlf>price=100)
root/0_books/0_author/1_book/attr.txt(content:title=走れメロス<crlf>price=90)
root/0_books/1_author/attr.txt(content:name=尾崎紅葉)
root/0_books/1_author/
0_book/attr.txt(content:title=金色夜叉<crlf>price=200)

これであれば、元のxmlを完全にフォルダ構造から復元できる

====ここからChatGPTの答え

このアプローチは、元のXML構造を完全に再現するために非常に有効です。アトリビュートやタグ内のテキストの順序も維持できるため、正確な復元が可能です。また、プレフィックスとして番号を付けることで、同じタグ名を持つ要素の区別も明確になります。

この方法での実装は非常に理にかなっています。次に、具体的にそのフォルダ構造を生成し、XMLをファイルシステムにシリアライズするためのPythonコード例を示します。

### Pythonコード例
```python
import os
import xml.etree.ElementTree as ET

def serialize_element(element, parent_path, prefix):
    # Create directory for the current element with prefix
    dir_name = f"{prefix}_{element.tag}"
    dir_path = os.path.join(parent_path, dir_name)
    if not os.path.exists(dir_path):
        os.makedirs(dir_path)
    
    # Write attributes to attr.txt
    if element.attrib:
        attr_file_path = os.path.join(dir_path, "attr.txt")
        with open(attr_file_path, 'w') as attr_file:
            for key, value in element.attrib.items():
                attr_file.write(f"{key}={value}\n")
    
    # Write inner text to inner.txt if it exists
    if element.text and element.text.strip():
        inner_file_path = os.path.join(dir_path, "inner.txt")
        with open(inner_file_path, 'w') as inner_file:
            inner_file.write(element.text.strip())
    
    # Recursively process child elements with a numerical prefix
    for i, child in enumerate(element):
        serialize_element(child, dir_path, i)

# Load XML
xml_string = """
<books>
    <author name="太宰治">太宰の作品
        <book title="人間失格" price="100"></book>
        <book title="走れメロス" price="90"></book>
    </author>
    <author name="尾崎紅葉">
        <book title="金色夜叉" price="200"></book>
    </author>
</books>
"""
root = ET.fromstring(xml_string)

# Define the base directory where the XML will be serialized
base_dir = 'output_dir'
if not os.path.exists(base_dir):
    os.makedirs(base_dir)

# Start the serialization process
serialize_element(root, base_dir, 0)
```

### フォルダ構造生成結果
上記のPythonコードを実行すると、次のようなフォルダ構造が生成されます:

```
output_dir/
└── 0_books/
    ├── 0_author/
    │   ├── attr.txt (content: name=太宰治)
    │   ├── inner.txt (content: 太宰の作品)
    │   ├── 0_book/
    │   │   └── attr.txt (content: title=人間失格\nprice=100)
    │   └── 1_book/
    │       └── attr.txt (content: title=走れメロス\nprice=90)
    └── 1_author/
        ├── attr.txt (content: name=尾崎紅葉)
        └── 0_book/
            └── attr.txt (content: title=金色夜叉\nprice=200)
```

### この方法の利点
- **順序保持**: XMLの要素やアトリビュートの順序が保持され、正確に再現可能。
- **明確な階層構造**: 番号付きのフォルダ構造によって、同一タグ名の要素も正確に区別できる。
- **シンプルな再構築**: フォルダ構造から元のXMLを再構築するのが容易。

これで、XMLデータを正確にシリアライズおよびデシリアライズできるシステムが実現できます。

2024年8月10日土曜日

散水機付けてみました

散水機付けてみました

自分が外出してたら水あげられないので
今後はどうしても必要になります

弁が四つついてて

NOWボタンで現在時刻を合わせ
ABCDで弁を選びます
選んだらOFF長押しでタイマーOFF
蛇口マークでマニュアルで弁を開きます(その際開いてる時間を指定)
プラスマイナスは時間の調整
OKはカーソルを次に送るボタンです

タイマーは何時に弁を開くか
何分開くか
何時間おきにタイマーを繰り返すか
と言う設定が出来ます

値段は最後の写真にありますが
ホースが足りなくて
Amazon探したら同じ物が同じような値段で合ったので追加購入してます(まだセットアップが残ってます)










2024年7月31日水曜日

構文木

5÷(8−3)×2+1を正しく計算できる?

というやつだ

答えは3なんだけど、
LRで構文木を作ると

まず、Rを探しに行く
右端は+ 1
                    PLUS
                /                \
       5/(8-3)*2           1

続いて、LからまたRを探すと、* 2

                    PLUS
                /                \
            MUL             1
          /          \
5/(8-3)      2
さらにLの5/(8-3)にRを探すと/ (8-3)

                   PLUS
                /               \
            MUL           1
          /           \
       DIV          2
     /       \
   5      8-3

んで、今度はR側にまだ再帰できるところがあるので

                   PLUS
                /               \
            MUL           1
          /           \
       DIV          2
     /       \
   5      MINUS
           /             \
         8              3
これで構文木が完成

そんで、答えを出すには最下層から上に上がっていく
8-3=5なので
                   PLUS
                /               \
            MUL           1
          /           \
       DIV          2
     /       \
   5         5

続いて
 5/5=1なので
                   PLUS
                /               \
            MUL           1
          /           \
        1          2
 
さらに続けて
1*2=2となり
                  PLUS
                /               \
              2                1

最後は
2+1=3
という事で、答えの3が導ける

ここで、数式とプログラミング言語を比べると、C言語なんて関数なので、

例えばif文
if (a==b) {
    proc();
}

          if
       /       \
    ==    proc()
   /      \
a        b

のようになるし、forも代入も似たようなもんで、構文木を作って解釈して行くことになる

このやり方はクヌース大先生が考案したもので、その後多くのアイデアが出てくるのだけど、基本はやはり構文木を作るというやり方になっている

そして、lexやyaccが生まれ、
構文木を自動生成するためにBNF記法が生まれ、C言語などのプログラミング言語が出来た

C++では構文定義をC++の記法で置き換えたboost::spiritsなども生まれ、すぐにこの変態的実装はなくなるかと思ったが、C++17でも残ってる

lexやyaccは
flexやbisonになったが
わたしが最近触っているANTLRは構文定義からGoやSwiftのコードも出力できる

好みの言語で新しい言語を作ることができるようになってきた

2024年7月20日土曜日

XML2Json再考

突然思い出したので
忘れないうちに書いておきます

Xerces Xalan
今はなかなか見かけない
この2つのプロジェクトは
XMLを扱っていた人ならご存知でしょう

実装の中身を見ていませんが
XMLをDOMとして扱っておらず
逐次的に処理をする実装になっていると聞いたことがあります

DOMについて
公式での解説も何だかパッとしないので改めて説明します

DOMと言うのは、XMLのツリー構造を構造体などを利用してメモリやファイルなどに保存しておいて、高速にアクセスすると言う仕組みです

例えばHTMLはブラウザでツリー構造が扱えるようになっていて、そのためにDocument.getElenentByIdのようなアクセスが可能となっています

これに対してDOMでは無いパースとは、XMLを単なるテキストとして扱い
上から順にパースして該当項目を探すので
あまりパフォーマンスは良くありません

このようにXerces Xalanは逐次的にパースするので
XMLを一度DOMとしてメモリやファイルなどに展開する時間はゼロです

巨大なXMLを扱う場合にはそれをDOMとしてメモリやファイルに保存しないため、メモリやファイルの消費を抑えることが出来ると言う利点もあります

なぜ突然この二つを思い出したのかと言うと、、、

わたしが以前Goで作ったXML2Jsonの実装を見ていて
DOMでは無い方が良いかも知れないと思い始めていたからです

当時の実装は逐次的にXMLのパースを行うGoのライブラリを使用して、XMLのTokenを取得しながら自前のDOMを作り、そのDOMからJSONに変換すると言う実装でした

しかもその変換関数は再帰ルーチンとなっていました

どうも無駄だらけに見えてきました

やはり一度作ったプログラムは何度か作り直さないとダメです

わたしは天才ではありません