組み込みキャンパスOJT開発記録#003

前回

shore01.hatenablog.com

5/15

授業を2つ倒したり、パーザージェネレーターを作ろうとしたり、.NET7.0へのアップデートをしたりしてました。 (生文字列リテラルが使えなくて気が付いた)

なのでCOJT関係の開発はなし。

5/16

相変わらずパーザージェネレーターを書いてます。 静的意味解析でTypeErrorが見つかるのって素晴らしく良い。

というわけで同じくCOJTの開発はなし

組み込みキャンパスOJT開発記録#002

前日

shore01.hatenablog.com

どうも、Shoreです。今日もChrome拡張機能を学びます。

本日5/14はつくばフェスティバルに行ってきました。

fes-tsukuba.com

インドネシアとかインドとかタイとかいろんな国の方の出店があり、非常に複雑な面白い香りがして楽しかったです。ですが出店に並ぶのが面倒だしやっぱ高いのでベーコンとパストラミを買いました。ベーコンしか食べてませんが、非常にスモーキーで美味しかったです。

閑話休題

5/14

今日はだらけたので22時からやり始めてます。明日は1限あるし2時間ぐらい集中してやって寝ます。

今日の目標は昨日のタブをグループ化するやつをONにしている間、常に自動的に行うようにすることです。

これを実装するために必要な動きは次の通り。

  1. タブの追加、削除、ページ遷移に合わせて機能のグループ化メソッドを動かす
  2. バックグラウンドで動くように変更する
  3. アイコンからON/OFFできるように変更する

ということで始めます。

バックグラウンドで動かす

まずは1. をやっていきますか。

chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
  const isRegroup = ["added", "removed", "changes"].includes(changeInfo.status);
  if (isRegroup) {
    await tabsGrouping();
  }
});

あれ、動かない。

またパーミッションかな?と思いbackgroundを追加。どうだ。

{
~~~~
  "permissions": ["tabs", "tabGroups", "background"],
  "host_permissions": ["<all_urls>"],
  "background": {
    "service_worker": "scripts/background.js"
  }
}

う~ん、動かない。console.logも動いてないから呼び出しがそもそもされていないっぽい?

エラーも出ないし。えぇ……

{
~~~~
  "permissions": ["tabs", "tabGroups", "background"],
  "host_permissions": ["<all_urls>"],
  "background": {
    "service_worker": "scripts/background.js",
    "type": "module"
  }
}

書き換えてみたけど動かない。

調べてみたらバックグラウンドで動いてる拡張機能console.log()の出力先が違うだと?!

一歩前進したのでここからはprintfデバッグなどを用いて原因究明へ。

あ~、対象にするべき changeIngo.status が違ったのか。変更したら動いた。

……けどタブを開くたびにグループを作り直しているから鬱陶しいこと甚だしい。練習用だし妥協してもいいけど。(追記:いろいろしたけど放置することに。groupにaddしたらうまくいくのかな。ワカラヌ)

ON-OFFをするのは比較的すぐに完成。

しかし、ページの削除で発火させるのを忘れてたので追加。

で、あーだこーだして完成。

作ったものとしてはこんな感じのことをする。

  1. タブを開いたり閉じたりするのに合わせてタブをドメインごとにグループ分けする
  2. アイコンをクリックすることでONとOFFを切り替えられる

総評

書いたはいいけど使い物になるかと言われるとNOだし、何よりコードの可読性がバイバイしてる。

精進せねばなぁ。

以上、お休み。

追記:今回作成したやつはGithubに公開してるのでいくらでも罵声を浴びせてください。アイコンがGoogleが公開してるやつそのまんまなのは許して。

github.com

組み込みキャンパスOJT開発記録#001

どうも、Shoreです。

組み込みキャンパスOJTというものに、受かってしまいました。なんてこった。

しかも、たぶんプログラミングができる人間だと思われてます。なんてこった

 

導入

こちら、ハードウェアコースとソフトウェアコースに分かれて学習し、それを基に何かを開発するってやつです。私はソフトウェアコースで、春はWeb関係をやる感じ。

詳しくは次のページを見るとよさそう。

szk18.hatenadiary.jp

 

始まって1カ月ほどたちまして、実際に何を作るかを考え始める時期になり、昨日5/12に『よし、作ろう!』という案がある程度固まりました。その名も******!!

 

暫定メンバー(たぶん変わる)はなんと豪華、いなにわうどん氏とちゅるり氏!! どちらもWeb経験豊富だし拡張機能開発の経験あり!ガハハ勝ったな!

 

いなにわ「学習することが重要だし開発はShoreさんがやってね」

ちゅるり「俺はタスク管理やるわ」

いなにわ「じゃあUIやろうかな」

わたし 「……困ったらヘルプはお願いします」

 

というわけでコーディングは私がメインでやることに。不味いですね。

 

というのも、Webは授業で触ったくらいだし拡張機能もちょっと触って違うこと (Unity) を始めたので経験値が0。そしてC#以外まともに書いていない。

 

 

というわけで、急いで学習を開始します。幸い時間は潤沢(*要出典)なので行けるはず。まあ去年もこんな感じだったけど何とかなってたしいけるでしょう、うん。

 

このブログは何か

自分の学習進度を共有してヤベーやつらに間違っている学習をしてたら指摘してもらうために書いてます。

あとはこのごろかなり怠けてたので矯正するために晒しています。

 

5/13

とりあえず信用できるサイトを探してそれを参考にしながら練習をすることに。

 

Getting Started Guidesを触ろう

公式のチュートリアルを発見したのでそれをパクリ、コードを7割がた理解することに。

 

Run scripts on every page

developer.chrome.com

コピペでとりあえず動くものはできたのでコードを理解するフェーズへ。

 

content.js の1行目から見慣れないものが出てきた……やってることはarticleを選択してるんだろうけど全部取ってるのか最初なのかわからない。

documentクラスの操作知っておかないと不味そうだからざ~っくりと調べておくことに。

Document - Web API | MDN

 

まあなんかいろいろやれることは分かった。こまめに発見した都度参照することにしよう(これを全部覚えるのは無理)

で、そのあとはarticleにいろいろしてるっぽいのでElementクラスのドキュメントもタブに開いておくことに。

Element - Web API | MDN

 

うん?ElementにtextContentが書かれていないな?

と思ったら基底クラスに定義されていました。

Node: textContent プロパティ - Web API | MDN

ついでに注意事項として次のようなことが書かれている。

 

innerText との違い

Node.textContent と HTMLElement.innerText の間の違いに混乱しないでください。名前は似ているようですが、重要な違いがあります。

  • textContent は、<script> と <style> 要素を含む、すべての要素の中身を取得します。一方、innerText は「人間が読める」要素のみを示します。
  • textContent はノード内のすべての要素を返します。一方、innerText はスタイルを反映し、「非表示」の要素のテキストは返しません。
    • もっと言えば、innerText は CSS のスタイルを考慮するので、innerText の値を読み取ると最新の計算されたスタイルを保証するために再フローを起動します。(再フローは計算が重いので、可能であれば避けるべきです。)

innerHTML との違い

Element.innerHTML は、その名が示すとおり HTML を返します。時に、innerHTML を使用して要素内のテキストを受け取ったり書き込んだりすることがありますが、textContent は値が HTML として解析されないので性能が良くなります。

さらに、textContent を使用することで XSS 攻撃を防ぐことができます。

一瞬人間が読める、ということを考えるならinnerTextのほうが良いのでは?と思ったけどtextContentは基本不変っぽいからそっちのほうがよいってことかな。

 

他にもXSSというものについても書いてあり興味があったのでざっくりと読んだ。

Cross-site scripting (クロスサイトスクリプティング) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN

クロスサイトスクリプティング - Wikipedia

 

他は理解した気になれたのでOK

 

そしていなにわさんが作っていたコードを見てみると、なんとな~く何をしてるか理解できた、気がする。ヨシ!

Inject scripts into the active tab

Chrome Extensions Tutorial: Focus Mode - Chrome Developers

アーハイハイナルホドネー

 

JavaScriptのほうはなにやってるかは分かってる、と思うのでOK!

CSSが、何を言っているかま~ったくわからない!

 

ということでBard君に説明してもらいました。

bard.google.com

 

非常にわかりやすい説明が、出てきた。けど前提知識がないのでちゃんとドキュメントを確認。

CSS セレクター - CSS: カスケーディングスタイルシート | MDN

ざっく~りとみてなんとな~~く理解。

 

拡張機能についての勉強もだけどCSSについてもちゃんとしないといけないなぁ……と感じた次第です。

 

Manage tabs

Manage tabs - Chrome Developers

Bard君を多用してメソッドの意味とかを随時調べながら実際に作った。やってることが割とUnityっぽい?から割とすらすら飲み込めた。

まあ分かった気に慣れたのでいいでしょう。うむ。

 

これ結構面白いことができそうだからもう少し触ってみることに。

 

お遊び開始

Manabaに対応させる

Manabaのタブをグループ化できた

まあ単純に対応個所書き換えるだけですし簡単。

 

ドメイン名ごとにグループ分け

まあこれもドメインをキーにした辞書型使えば一瞬……

 

できない。なぜ?TypeError: Failed to construct 'URL': Invalid URLが出続けるぞ?

 

⌚数十分経過

 

permissionsの問題だったぜ……

 

というわけで完成

完成!

 

まあ初日の進捗としては……いいでしょう。

 

終わり

まあ今日はこんくらいで……

なんとな~くわかった?気がしないでもない?って感じなので自力で開発できそうかな?

 

これからも頑張ります。(明日はパーザー作るかもしれない)

プログラミング課題不正回答を防ぐ手法の提案

この記事は、mast Advent Calendar 2022の23日目の記事です。

 

22日目はちゅるりさんがなにか書くはずです。

 

どうも、mast21のShore(しょあ)です。興味がある分野は高校におけるプログラミング学習、および教育用プログラミング言語です。

枠が空いてたので2つ目の記事になります。前回の記事は次のものです。

shore01.hatenablog.com

 

今回の記事は題目の通り、前回よりは真面目、と思いきや結構ふざけたこと書いてます。真面目な文章は秋Cに書かないといけないので頑張らねば……

 

1. 導入

 

さて、AI使って課題、作成してますか~?(いえ~い!!!)

今回はAIを使って課題をする、ということに関する倫理的問題については議論しません。

 

先日、CE研の167回研究発表会を聴講していたら次のような研究発表がありました。題名は『オンライン試験における不正抑止システム』です。

ipsj.ixsq.nii.ac.jp

内容はまだ会員しか無料閲覧できないので割愛しますが、この発表と教授らの反応を見てると、「あ~、皆課題の不正嫌いなんだな~」って感じました(当たり前です)。で勿論私は、プログラミング講義における不正について考えを巡らせるわけです。

 

🤔.。○〇(なんちゃらソートを改変したやつとかを課題として出す、とかかなぁ?)

 

そんな時にChatGPT君の登場! なんとコードも書いてくれる! すげえ! これに仕様ぶち込んだらコード書いてくれる! もう人間がコードを考えなくてもAIにぶち込んで体裁整えてレポートを作ればよい! 感動できる!!!

 

 

さて、どうしますか?という話。

 

Webの閲覧を禁止します?

別にCopilot君で似たようなことできますね~。てか別端末で見ればいいし。

 

疑似コードで書かせます?

実行できないプログラムとかプログラミングできる人でもミスするし採点やってられませんよね?

 

対面でやります?

まあいいんじゃないですか?けどレポート課題出せませんね。

 

2. 提案手法

このAIによって生み出されたプログラミング教育の問題を解決する、画期的な手法を提案します。

 

はい。

 

2.1 どうゆうこっちゃ

そもそも、ChatGPTやCopilotは何をしているか、というと基本的には過去の膨大なコードを分析して推定しているわけです。つまり、『学習していない言語であれば書けない』。

 

なので、作りましょう。学習されていない言語を。

 

2.2 場面設定

実用場所として弊学の講義であるデータ構造とアルゴリズム実習を設定します。この講義はソートや二分木などのコードを書くものです。コンソール実行ができればよいのが良いですね。

 

2.3 方法

インタプリタを作成します。

仕様としては次の通り。

  • 正規表現を用いて書かれた字句定義ファイルを読み込むことで字句解析を行う
  • 文法を構文定義ファイルから読み込むことでパースする
  • 様々な個所に変更可能点を作成する。
  • パースした結果作成されるASTは同じであるようにする

 

字句定義ファイルを読み込んで解析!

例えば、

INT::=[0-9][0-9]*

のように書かれている、BNF記法風の定義ファイルを読み込んで字句解析をする。教員側が変更するのが簡単!やったね!

 

文法もファイルを読み込んで解析しよう!

例えば次のような記法で文法を定義します。

<FOR>::=name num num num ::=NAME (WO) num (KARA) num (MADE) num (ZUTSUFUYASHINAGARAKURIKAESU COLON)

 

左から、構文名、AST設定、構文設定です。

こんな感じにすれば教員側が文法を変更するのが簡単!やったね!

 

様々な個所に変更可能点を作成する

例えば、

  • for文がfor文してたりforeachしてたり
  • forの終了条件数字まで演算したりその一つ前までだったり
  • インデックスが0から始まったり1からだったり
  • インデックスをマイナス指定できたりできなかったり
  • 文字列をインデックスで指定できたりできなかったり

というのを教員側が設定できるようにするわけです。

 

パースしたAST

処理系を毎年書き換えるのはめんどくさいので固定にします。つまり、外見は違う言語だけど処理は全く同じってわけですね。なでしことおんなじ、なのかな?

 

3. どうなる?

次のことが防止できます。

 

3.1 先輩の出した課題をもらってそれを提出する!

だって去年と文法違うから丸写しできない!

(これを疑って課題点を0にした教員がいましたねぇ……的外れでしたが)

 

3.2 ChatGPTに解いてもらう!

だって学習してない言語だもん!

 

3.3 Copilotに頼る!

学習してない+言語仕様の細かいところをいじれるからセグフォ出しまくりになる!

 

4. 結論

やったね!これで学生は自分でコードを書かざるを得なくなるよ!

AIが課題をする、なんてこともできなくなる!

 

学生同士で教えあい、まで防止したかったら構文設定、字句設定ファイルを学生ごとに乱数で生成して渡せば防止できる!これで完璧だ!!!

 

 

5. 追記

技術的にはこのように完全にAIなどを用いた講義課題不正回答の防止を行うことはできます。実際に実験をしていないので断言はできませんが、かなり強度が強いと思います。

 

けど、ここまでする必要ありますかね?不正を防止するのもそりゃあ重要ですが、それよりも内的動機により学習を行うよう、教材に工夫をする、とかのほうが建設的な気がします。

あと、この方法使うと講義で学んだ内容を全くほかの場所で使えないのもよくない。学んで終わり。さあ次の実用的な言語ってなる。

 

けど、大学って実学じゃない部分を学ぶことにも意義があって、そこをやらないなら専門学校もろもろでいいじゃん、ってなるのは確かにそうなんだよなぁ。難しい。

 

 

以上。皆様良いお年を。

プログラミング初心者が最初の個人プロジェクトとしてプログラミング言語を作ったことについて

この記事は、mast Advent Calendar 2020 の3日目の記事です。
2日目は紫葉さんの記事『believeの中にはlieが入っているという話を聞きました! - ふわり、と浮いています。』(好きなもの紹介)でした。

 

皆さんこんばんはこんにちは、mast21のShoreです。

 

今回の話題はタイトルの通り、プログラミング初心者が右も左もわからない状態からなぜかプログラミング言語を作ったので、作る間に何が起きたか、というのを書いていきます。

 

まず、前提として何をしたかを話しますと

  1. 去年は怖くて取らなかったけど、情報メディア特別演習という講義を今年は取ってやるぜ!
  2. テーマどうしようか…… よし、プログラミング言語の学習環境を作ろう!
  3. そのためには実行系と言語が必要だな!←?
  4. 作るか!←????
  5. プログラミング言語C#でそのインタプリタを作った!←??????????

って感じです。今考えると頭がおかしいのではないか、と思わざるを得ない。

 

ちなみに作った実行系に関する話とか言語とかの話は今回はしません。今回は、4→5の間に起きた、ヒヨコだったころの私がやらかしたことについて赤裸々に話していこうかと思います。

 

では、始めます。

 

プログラミング言語そのものに対する知識不足

ここからはプログラミング言語というものに対する知識がなかったために起きた問題を書いていきます。

4~5月: 構文解析、字句解析?なにそれおいしいの?

でしょうね~~~~~~~~~!!!!!!!

まず最初の問題は圧倒的知識不足でした。

当時の私は、Pythonを用いた授業であるプログラミング入門ABの知識と夏休み中のその予習、そして冬休みにちょろっとC#を触った経験だけ!(一応C言語を触った経験はあったのですがほんの少し。)

そんな人間が構文解析器なんて作れるはずも……

 

いやこれが意外にうまく行っちゃったんですよ。たちが悪いことに。

当時の私はなんと1000行ほどのクラスに字句解析、および構文解析器を途中まで作成しました。たぶんあのまま言ってたらキメラのような構文解析器を完成させてましたね。

 

これと同じことが今後も続きます。すなわち「知識ないのに調べないで我流ですべてを完成させようとする」というムーブをかましまくります。

 

ですが、ま~問題だらけの方法を使ってまして。

  1. クラスを構造体のように使い、字句を値と分類のトークンに分けるなんてもちろん知識にないので、値と分類を合わせた一つの文字列型として保持する。
    例:
    入力→"hoge = \"fuga\""
    出力→{"variable:hoge", "operator:=", "string:\"fuga\""}
  2. 構文解析器において、文法の問題で行頭のみでは構文を決定できなかったのであるワードが行に含まれているかでどの文法か、を判断する。
  3. もちろん構文解析木なんて言葉は知らないので実行時にリストの値を再帰的に分割しながら実行する。
  4. 関数にほとんど分けてなかったのでmain関数1つの中で上をほぼしてる。

いや~、すごい。当時の教員と先輩の苦笑していた理由がわかる。すごい間違ってる。

 

6月: 汎用的な構文解析器を作れ? できらぁ!

「ちょっと」勉強しました。そして私はこんなことを言ってしまいます。

「ある程度ほかの言語実行系を作るときに流用できるやつを作りたい」と。

そして担当教員にも「やろう!」と言われました。

 

さ~てこう言われた私は考えます。そもそも文法の記法はどうしようか。どうしたらより楽に構文解析のための文法記法の構文解析を行えるだろうか、と。そして私は閃きます(閃くな)。

 

「そうだ、正規表現みたいに文法を記述することにすれば簡単に構文解析器を作れそうだぞ!」と。

 

作りました。完成させちゃいました。バックトラックもりもりの、却ってLL(1)構文解析器作るよりも面倒なものを作ってしまったのです。意気揚々とそれをもってMTに当時の私は向かいます。

構文解析器をつくったよ~! 文法はこんな感じで書いたら文法を記述しているファイルを読み込んで構文解析木を生成してくれるよ~!」

「ちょっと話を聞かせてくれるかな。何してるの?」

 

ということでまたやらかしました。その名も「調べずに我流で書いてたら正規言語の構文解析もどきを作ってたぜ!」です。逆にすごいな……

 

その後

その後は(比較的)普通のLL(1)構文解析器を作って実行系を作って終わりました。めでたしめでたし。確か春Cが暇だったから1か月くらいで完成させたんだったか?

 

プログラミングの知識不足

ここからはプログラミング技術が乏しいためにやらかしたミスを赤裸々に思い出しながら綴っていきます。

1. 複数の情報を持つ値、うーん?

上で書いた通り、クラスや構造体は知識では知っているものの使い方を知らない状態でしたので……

2. static属性ってなんすか?

なんと、すべての関数を動的メソッドとして宣言していたので、毎回呼び出すたびにクラスを宣言してました。いや、なんかC#って面倒だな、とは思ってたんだよ。思っただけで調べなかったけど。

3. ネームスペース?なんかかっこいい!

ネームスペースをむやみやたらに分けまくってました!具体的には、MainとLexerとParserとExecuteとExecute.Functionと……って感じになってました。なんかnamespaceたくさんあるとかっこいいじゃん!

 

まとめ

まず、情報メディア特別演習は悪くないです。なんなら非常に良い機会なので皆さんやる気があるなら取りましょう。ぜひ。正直去年取らなかったのを後悔している。

 

今回はやらかし先生として記事を書いているわけですが、学びとしては「やりながら学ぶ、というのも結構だけどちゃんと勉強もしましょう」ですね。こんなことになった理由の一つに、毎週MTがあったので進捗を出さねば、という強迫観念を勝手に抱いていたことがあると思います。別に、○○を勉強しました、でもよかったのに。焦っていたのでしょう。

皆さんは私みたいにならず、一歩先くらいは見える状態から始めるとよいと思います。

 

最後に。

この記事を書いていくうちに自分の愚かさに気が付くとともに呆れずに指導してくれた担当教員にありがたい気持ちと申し訳ない気持ちに改めてなりました。SNSをやらない方なのでおそらく読んでいませんが感謝いたします。

 

以上