ときどきの雑記帖 RE* (新南口)
夏の魔術
21H1
ようやく20H2(だったと思う)から上げた。 ちらほら大嵌りしたというのを見聞きしていたので、 こわごわとやったのだけどあっさり終わった。
shell
シェルとシェルスクリプトについて面白い記事を書き続けている人発見。
fishは(まあ、記事の性格を考えれば当然ではあるけれども)スルーっぽい。
ジャングル
タイガーマスクのOP曲、1~3番の歌詞のそれぞれの出だしを抜き出すと
- 白いマットのジャングルに
- 三本ロープのジャングルに
- 草も木もないジャングルに
…一体どんなイメージ持ってたんだ>ジャングル
と思ったら。
上記に転じ、無法地帯の形容。
〔a [the] ~〕((俗))冷酷な競争社会;暴力の場
へー。
parser
各言語実装が、自家製の構文解析器を使っているか、あるいはYacc的なパーサジェネレータを使っているかの調査。
— 新山祐介 (Yusuke Shinyama) (@mootastic) August 22, 2021
自家製: GCC, Clang, JS V8, TypeScript, OpenJDK, Go, C# Roslyn, Lua, Swift, Julia
Yaccもどき: Ruby, PHP, Bash, R, PostgreSQL, MySQL, SQLite
PEG: CPythonhttps://t.co/TlguNesqEu
で言及されている Parser generators vs. handwritten parsers: surveying major language implementations in 2021 | notes.eatonphil.com を見たけど、Rubyの
Ruby: Yacc-like Parser Generator
Ruby includes a Yacc-like parser generator called racc. The grammar for the language can be found here.
これはなんか違うような?
Rubyがその構文解析器でbison(yaccでは処理できないものになっていたと記憶しているのでこう書く)を 使っているのは間違いないけど、raccってRubyで書かれたプログラム用の yacc的なものであってRubyインタープリターそのものの実装とは関係ないと思う。
Racc は文法規則から Ruby で書かれたパーサを生成するパーサジェネレータです。 パーサ生成アルゴリズムには yacc などと同じ LALR(1) を使用しています。
xargs
なんかタイミングよく。
glob zsh 10
ちょっと間が空いたけど 前回 の続き。
q = parsepat(str);
if (!q || errflag) { /* if parsing failed */
restore_globstate(saved);
if (unset(BADPATTERN)) {
if (!nountok)
untokenize(ostr);
insertlinknode(list, node, ostr);
return;
}
errflag &= ~ERRFLAG_ERROR;
zerr("bad pattern: %s", ostr);
return;
}
if (!gf_nsorts) {
gf_sortlist[0].tp = gf_sorts = (shortcircuit ? GS_NONE : GS_NAME);
gf_nsorts = 1;
}
前回はここまで見た。
その続きはこう。
/* Initialise receptacle for matched files, *
* expanded by insert() where necessary. */
matchptr = matchbuf = (Gmatch)zalloc((matchsz = 16) *
sizeof(struct gmatch));
matchct = 0;
pattrystart();
/* The actual processing takes place here: matches go into *
* matchbuf. This is the only top-level call to scanner(). */
scanner(q, shortcircuit);
/* Deal with failures to match depending on options */
if (matchct)
badcshglob |= 2; /* at least one cmd. line expansion O.K. */
else if (!gf_nullglob) {
if (isset(CSHNULLGLOB)) {
badcshglob |= 1; /* at least one cmd. line expansion failed */
} else if (isset(NOMATCH)) {
zerr("no matches found: %s", ostr);
zfree(matchbuf, 0);
restore_globstate(saved);
return;
} else {
/* treat as an ordinary string */
untokenize(matchptr->name = dupstring(ostr));
matchptr++;
matchct = 1;
}
}
コメントにある通り、真ん中より少し前で呼び出している scannerが globingの本体とも言えるところなんだけど、 それゆえちょっと長めの関数なので zsh/glob.c at 00d20ed15e18f5af682f0daec140d6b8383c479a · zsh-users/zsh 処理スタックに積んでおいて先へ。
scanner を呼び出す前に意味ありげに matchptr、matchbuf、matchct という変数を操作しているけれど これは以前にちょっと触れた
zsh/glob.c at master · zsh-users/zsh
#define matchsz (curglobdata.gd_matchsz)
#define matchct (curglobdata.gd_matchct)
#define pathbufsz (curglobdata.gd_pathbufsz)
#define pathbufcwd (curglobdata.gd_pathbufcwd)
#define matchbuf (curglobdata.gd_matchbuf)
#define matchptr (curglobdata.gd_matchptr)
#define colonmod (curglobdata.gd_colonmod)
この辺の、情報を管理する構造体のメンバーに対するマクロ。 scaner を呼び出した後すぐのif文でmatchctを 参照しているので、scannerの中でも参照したり操作したりしているんでしょう。
この後は
if (!(gf_sortlist[0].tp & GS_NONE)) {
/*
* Get the strings to use for sorting by executing
* the code chunk. We allow more than one of these.
*/
int nexecs = 0;
struct globsort *sortp;
struct globsort *lastsortp = gf_sortlist + gf_nsorts;
Gmatch gmptr;
から始まるちょっと長めのif文のブロックなので 短めだけど今回はここまで。
x
google/zoekt がメモリ最適化によりメモリ使用量を1/5にした話。 / “A 5x reduction in RAM usage with Zoekt memory optimizations” https://t.co/Sm7yA8cBrT
— mattn (@mattn_jp) August 21, 2021
A 5x reduction in RAM usage with Zoekt memory optimizations
「1/5にした」は「A 5x reduction」ですか。 10x で10倍みたいな使い方しか見てなかったので(たぶん)、 reductionがついているからそうだと理解できてもちょっと違和感あるな😄