One True Awk
これまでの記事 で自作プログラムを動かすことができるようになったので、OSS のプログラムを移植してみる。
ネットワークやデバイスが関連するものは難しいと思うので、テキスト処理をするものとして One True Awk を選択した。
本来は makefile を移植するのがセオリーかもしれないが、ビルドに bison が必要だったり、maketab.c をコンパイルしたものをツールとして使っていたりするので、Windows の環境で実現するのには手間がかかる。
そこで Ubuntu Linux を使って 公式の資料 に従い、以下のように生成したソース・ファイルを Windows に配置した。
ubuntu@vm1:~$ git clone https://github.com/onetrueawk/awk.git
Cloning into 'awk'...
remote: Enumerating objects: 2335, done.
remote: Counting objects: 100% (673/673), done.
remote: Compressing objects: 100% (211/211), done.
remote: Total 2335 (delta 524), reused 462 (delta 462), pack-reused 1662 (from 2)
Receiving objects: 100% (2335/2335), 4.12 MiB | 6.11 MiB/s, done.
Resolving deltas: 100% (1365/1365), done.
ubuntu@vm1:~$ cd awk
ubuntu@vm1:~/awk$ make
bison -d awkgram.y
awkgram.y: warning: 44 shift/reduce conflicts [-Wconflicts-sr]
awkgram.y: warning: 85 reduce/reduce conflicts [-Wconflicts-rr]
awkgram.y: note: rerun with option '-Wcounterexamples' to generate conflict counterexamples
cc -g -Wall -pedantic -Wcast-qual -O2 -c -o awkgram.tab.o awkgram.tab.c
cc -g -Wall -pedantic -Wcast-qual -O2 -c -o b.o b.c
cc -g -Wall -pedantic -Wcast-qual -O2 -c -o main.o main.c
cc -g -Wall -pedantic -Wcast-qual -O2 -c -o parse.o parse.c
cc -g -Wall -pedantic -Wcast-qual -O2 maketab.c -o maketab
./maketab awkgram.tab.h >proctab.c
cc -g -Wall -pedantic -Wcast-qual -O2 -c -o proctab.o proctab.c
cc -g -Wall -pedantic -Wcast-qual -O2 -c -o tran.o tran.c
cc -g -Wall -pedantic -Wcast-qual -O2 -c -o lib.o lib.c
cc -g -Wall -pedantic -Wcast-qual -O2 -c -o run.o run.c
cc -g -Wall -pedantic -Wcast-qual -O2 -c -o lex.o lex.c
cc -g -Wall -pedantic -Wcast-qual -O2 awkgram.tab.o b.o main.o parse.o proctab.o tran.o lib.o run.o lex.o -lm
以下のうち maketab.c 以外が Awk のソースコードとなる。
ubuntu@vm1:~/awk$ ls *.c *.h
awk.h awkgram.tab.h lex.c main.c parse.c proto.h tran.c
awkgram.tab.c b.c lib.c maketab.c proctab.c run.c
また、入力ファイルは適当に検索して見つかった address-sample.csv を利用している。
ubuntu@vm1:~/awk$ curl -sSLO https://raw.githubusercontent.com/geocommons/geocoder/refs/heads/master/test/data/address-sample.csv
ubuntu@vm1:~/awk$ ./a.out --csv 'NR!=1 {print $14,$11,$12;} NR>5 {exit;}' address-sample.csv
11211 Brooklyn
02903 Providence
03561 Littleton
04401 Bangor
04901 Waterville
ファイル一覧
VSCode の CMake プロジェクトを構成するファイルの一覧は以下の通り。
{
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "localhost:8080",
"url": "http://localhost:8080/",
}
]
}
cacheVariables にあった CXX 系のものは削除
{
"version": 5,
"cmakeMinimumRequired": {
"major": 3,
"minor": 20,
"patch": 0
},
"configurePresets": [
{
"name": "wasm-config",
"hidden": true,
"generator": "Ninja Multi-Config",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "$env{EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
"CMAKE_CONFIGURATION_TYPES": "Debug;Release"
}
},
{
"name": "wasm-config-debug",
"inherits": "wasm-config",
"cacheVariables": {
}
},
{
"name": "wasm-config-release",
"inherits": "wasm-config",
"cacheVariables": {
}
}
],
"buildPresets": [
{
"name": "wasm-build-debug",
"configurePreset": "wasm-config-debug",
"verbose": true,
"configuration": "Debug"
},
{
"name": "wasm-build-release",
"configurePreset": "wasm-config-release",
"verbose": true,
"configuration": "Release"
}
]
}
- project(LANGUAGES) では C言語 を指定している
- file(GLOB) により awk/ ディレクトリ以下の *.c をソースファイルとする
- --preload-file を使って、入力ファイルを仮想ファイルシステムの /address-sample.csv として配置
cmake_minimum_required(VERSION 3.20)
project(16_awk LANGUAGES C)
file(GLOB SOURCES "awk/*.c")
add_executable(16_awk ${SOURCES})
target_link_options(16_awk PRIVATE
$<$<CONFIG:Debug>:-gsource-map -sASSERTIONS=1 -sSAFE_HEAP=1>
"-sEXPORT_ES6=1"
# https://github.com/geocommons/geocoder/blob/master/test/data/address-sample.csv
"--preload-file=${CMAKE_SOURCE_DIR}/address-sample.csv@address-sample.csv"
)
- awk の main() 関数の引数に「--csv NR!=1 ...」を指定
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8"/>
<script type="module">
import Module from './build/Debug/16_awk.js';
const locateFile = (path, prefix) => {
console.log(`locateFile(path=${path}, prefix=${prefix})`)
if (path.endsWith(".data")) {
return './build/Debug/' + path;
}
return prefix + path;
};
const preRun = [
emsModule => { console.log('# AWK-START'); },
];
const postRun = [
emsModule => { console.log('# DONE.'); },
];
const args = [
'--csv',
'NR!=1 {print $14,$11,$12;} NR>5 {exit;}',
'address-sample.csv'
];
await Module({ arguments: args, locateFile, preRun, postRun });
</script>
</head>
<body>
</body>
</html>
C:\wasm\project\16-awk\awk\*.{c,h}
Linux で作成したソースコードを配置
C:\wasm\project\16-awk\awk>dir /B *.c *.h
awkgram.tab.c
b.c
lex.c
lib.c
main.c
parse.c
proctab.c
run.c
tran.c
awk.h
awkgram.tab.h
proto.h
C:\wasm\project\16-awk\address-sample.csv
ファイル を取得して配置。
実行結果
デバッガを実行しブラウザを起動すると、コンソールには以下のような出力が行われる。
Linux で実行した結果と一致していることが確認できる。
locateFile(path=16_awk.data, prefix=)
locateFile(path=16_awk.wasm, prefix=http://localhost:8080/build/Debug/)
# AWK-START
11211 Brooklyn
02903 Providence
03561 Littleton
04401 Bangor
04901 Waterville
# DONE.