-
Notifications
You must be signed in to change notification settings - Fork 5
OpeLa Language Specification
Kota UCHIDA edited this page Jan 5, 2021
·
41 revisions
IDT の 21 に割り込みハンドラを登録し,割り込み許可(sti)する例です。
// 構造体の定義
// foo[n] は特別な構文で,接頭辞 foo が共通するメンバがグループ化される
type idtEntry struct {
Offset[0] address16;
SegmentSelector uint16;
IST uint3;
_ uint5;
Type uint4;
_ uint1;
DPL uint2;
P uint1;
Offset[1] address16;
Offset[2] address32;
_ uint32;
};
// OpeLa の構造体にはパディング機能がないので明示的にパディングする
type stackFrame struct {
SS uint16;
_ uint48;
SP address;
Flags uint64;
CS uint16;
_ uint48;
IP address;
};
// グローバル変数
var (
idt idtEntry[256];
)
func notifyEndOfInterrupt() {
// 組み込みの Atomic 型を使ってレジスタアクセス
eoi *Atomic<uint32> := address(0xfee000b0);
eoi->Store(0);
// same as: *Atomic<uint32>(address(0xfee000b0))->Store(0)
}
// interrupt service routine
isr intHandler21(stackFrame *stackFrame) {
Printk("INT21 CS:RIP = {:02x}:{:08x}\n", stackFrame->CS, stackFrame->IP);
notifyEndOfInterrupt();
}
func main(argc int, argv *byte) {
idt[21] = {
.Offset = &intHandler21, .SegmentSelector = 1 * 8,
.Type = 14, .DPL = 0, .P = 1
};
idtr packed_struct { _ uint16, _ address } := { sizeof(idt) - 1, &idt };
intrin.Lidt(&idtr);
intrin.Sti();
for {
intrin.Hlt();
}
}
- int/uint: int64/uint64 の別名
- intN/uintN: N ビット幅の符号付き/符号無し整数
- byte: uint8 の別名
- address: ネイティブ幅のアドレス型(Intel 64 モードでは 64 ビット)
- addressN: N ビット幅のアドレス型
OpeLa では char
は組み込み型名ではない。
たとえ両辺が整数であっても、異なる型同士の計算はコンパイルエラー。
他の言語にない特徴的な型として address がある。アドレスはポインタから型情報を取り除いたものである。C の void*
に近い。
任意のポインタと address は相互に暗黙的に変換可能。
address から整数へは暗黙的に変換可能。
整数から address へは明示的なキャスト address(整数)
が必要。
var v uint2 = 1; v = v + 3;
では i は uint2、3 は int となる。型が異なるためコンパイルエラー。
正しくは var v uint2 = 1; v = v + uint2(3);
とする。
ちなみに、v はオーバーフローして 0 となる。
- type Name T: T という型に Name と言う名前を付ける。Name は T とは異なる型となる。
- struct {..}: 構造体型(パディングなし)
type Foo struct { ... }; // 構造体型に名前 "Foo" を付ける
var x struct { ... }; // 構造体型の変数 x の定義
ページエントリのアドレスフィールドのように,下位 N ビットをマスクして読み書きすべきフィールドを定義できる。
type PageEntry struct {
P uint1;
RW uint1;
US uint1;
PWT uint1;
PCD uint1;
A uint1;
D uint1;
PAT uint1;
G uint1;
_ uint3;
Addr address64[63:12];
}
func f() {
var e PageEntry
e.Addr = 0x12345
assert(e.Addr == 0x12000)
}
文字列は byte の配列として扱う。
文字列は,将来的には Go と同じように読み取り専用のスライスとして実装したい。 現状では文字列を変数に格納するためには,先頭要素のポインタを取得する必要がある。
p := &"abc"[0];
var x1 [3]int; --> int が 3 つ並んだ配列変数(初期値は不定)
x1[i]; --> 配列の i 番目の要素(i は 0 始まりの整数)
p := &x1[i]; --> 配列の i 番目の要素へのポインタ
初期値付き配列
var x2 [3]int = {1, 2}; --> {1, 2, 0} という初期値を持つ 3 要素の配列
以下,仕様考え中…
p := &x1; --> p は x1 の先頭位置と要素数を持つ
hsjoihs さんが EBNF で定義を書いてくださいました。 将来的には、これに修正を加えて OpeLa の仕様として使いたいですが、今はとりあえずリンクするだけ。
https://gist.github.com/sozysozbot/b973b6f592eb3e990f904f56584a43a7
- パターンマッチを実装するにはコンストラクタと型を結び付けておく必要がある https://twitter.com/takoeight0821/status/1303531973722304513
- Go の文字列は読み取り専用のスライス https://blog.golang.org/strings