言語仕様
Lambda C は組み込みスクリプティング向けに設計された C89 のサブセットです。本ページは、コンパイラ(lcvmc)が受理する言語表面と対象ランタイム — サポートする型・演算子・制御フロー・組込みライブラリ、そして意図的な非対応事項と実装上限 — を定義します。
言語がどのようにコンパイル・実行されるかは アーキテクチャ を、API と機能のカタログは 機能 を参照してください。
データ型
| 型 | サイズ | 備考 |
|---|---|---|
char | 1 B | 符号付き |
unsigned char | 1 B | |
short | 2 B | |
unsigned short | 2 B | |
int | 4 B | |
unsigned int | 4 B | |
long | 4 B / 8 B | ターゲット依存(LP64 対応) |
unsigned long | 4 B / 8 B | |
float | 4 B | |
double | 8 B | |
void | — | 関数の戻り値 / void * |
| ポインタ | 4 B / 8 B | int *、char ** …(ターゲット依存) |
型の幅はビルド時のターゲット設定(common.h の LCVM_TARGET_*_SIZE)で固定されます。64 ビットホストでは long とポインタは 8 バイト、32 ビット MCU では 4 バイトです。long long、_Bool、および C99 の固定幅型は非対応です。
演算子
| 分類 | 演算子 |
|---|---|
| 算術 | + - * / % |
| 比較 | == != < <= > >= |
| 論理 | && || ! |
| ビット | & | ^ ~ << >> |
| 代入 | = += -= *= /= %= &= |= ^= <<= >>= |
| インクリメント / デクリメント | ++ --(前置・後置) |
| 単項 | &(アドレス取得)、*(間接参照)、-、+、!、~ |
| メンバアクセス | . -> [] |
| その他 | sizeof、? :(三項)、,(カンマ)、(type) キャスト |
制御フロー
if (cond) { ... } else { ... }
while (cond) { ... }
do { ... } while (cond);
for (init; cond; step) { ... }
switch (expr) { case N: ... break; default: ... }
break;
continue;
return expr;
goto label;
宣言と定義
/* グローバル変数・静的変数 */
int global_var;
static int static_var;
char *string_ptr = "hello";
/* 関数: 定義とプロトタイプ。
パラメータ数に固定上限はなく、スタック容量のみで制限される。 */
int func(int a, int b) { return a + b; }
int external_func(int x);
/* 配列(多次元配列も最大6次元までサポート) */
int array[100];
char buffer[256];
int matrix[10][10];
int cube[4][4][4];
/* ポインタ(関数ポインタを含む) */
int *ptr;
char **argv;
int (*callback)(int);
/* 構造体と共用体 */
struct Point { int x; int y; };
struct Point p;
struct Point *pp;
union IntBytes { int value; char bytes[4]; };
/* enum: 明示的な値と無名 enum */
enum Color { RED, GREEN, BLUE };
enum ErrorCode { OK = 0, ERR = -1, ERR_IO = -2 };
enum { FLAG_A = 1, FLAG_B = 2 };
/* typedef */
typedef int INT32;
typedef struct Point Point_t;
/* const / volatile は認識されるが無視される(通常の型として扱う) */
const int LIMIT = 100;
volatile int flag;型キャスト
整数・浮動小数点・ポインタの間のキャストがサポートされます:
char c = (char)i; /* int -> char(切り捨て) */
double d = (double)i; /* int -> double */
int *p = (int *)ptr; /* ポインタの再解釈 */
char *b = (char *)&v; /* int のバイト表現ビュー */
注意点が一つあります。式の途中での int→double 拡張キャストは適用されません。浮動小数点オペランドで演算を行うか、いったん double 変数に代入してください。
プリプロセッサ
レキサが小さなインラインプリプロセッサを処理します。フル機能の C プリプロセッサではありません — スクリプトの合成とターゲットコードのゲーティングのために存在し、メタプログラミングを目的としていません。
サポート:
#include "header.h"
#include <stdio.h> /* 組込みヘッダー(標準ライブラリ参照) */
#define MACRO 100 /* オブジェクト形式マクロ: 数値 / 文字 / 文字列 */
#ifdef MACRO
#endif
#ifndef MACRO
#else
#endif
非サポート: #if / #elif、#undef、#pragma、#error / #warning、##(トークン連結)および #(文字列化)演算子、defined()、引数を取る関数形式マクロ。単純な数値・文字・文字列定数でない #define 本体は拒否されます。
標準ライブラリ
スクリプトは include/lcvm/ 配下のヘッダーで公開される組込み関数を通じてランタイムにアクセスします。以下の関数は VM イントリンシックとして実装されており、対応するヘッダーを #include するとプロトタイプが可視になります。
stdio.h
printf、sprintf、fprintf、scanf、sscanf、fscanf、getchar、putchar、getc、putc、fopen、fclose、fgetc、fputc、fgets、fputs。
stdlib.h
malloc、free、atoi、qsort、exit、abort。
管理ヒープはバンプ/リージョンアロケータです — malloc は確保しますが、個別ブロックの free は no-op です。一括回収は heap_mark / heap_release 拡張(後述)で行います。realloc は提供されません。
string.h
strlen、strcpy、strcat、strncat、strcmp、strncmp、memcpy、memset。
math.h(すべて double を扱う)
sin、cos、tan、asin、acos、atan、atan2、sinh、cosh、tanh、exp、log、log10、pow、sqrt、ceil、floor、fabs、fmod。
time.h
clock、time、difftime、mktime、gmtime、localtime、asctime、ctime、strftime。
search.h / glob.h / regex.h
bf_search、bf_re_search、bm_search、bm_re_search(総当たり / Boyer–Moore による文字列・正規表現検索)、amatch(glob マッチャ)、rx_search(正規表現検索)。
Lambda C 拡張
C ライブラリに加え、ランタイムは組み込みオーケストレーション向けのイントリンシックを公開します:
| 関数 | 用途 |
|---|---|
heap_mark() | 現在のヒープ位置(ウォーターマーク)を記録 |
heap_release(mark) | mark 以降に確保した全領域を一括解放 |
millis() | 経過ミリ秒(単調タイマー) |
lcvm_reset(vm) | VM の自己リセットを要求 |
vm_reload(reason) | スクリプトのホットリロードを要求 |
vm_interrupt(flag) | 協調的割り込みフラグを設定 |
関数を持たないヘッダー
limits.h と float.h は定数(INT_MAX、DBL_DIG …)のみを提供します。ctype.h、assert.h、stdarg.h、setjmp.h、signal.h はスタブとして存在し、動作する関数は提供しません — setjmp / longjmp はホスト側にのみ存在します。<stddef.h>、<stdint.h>、<stdbool.h>、<errno.h>、<locale.h> は存在しません。NULL には 0、bool には int、固定幅整数には明示的な typedef を使ってください。
静的型モード(-Os)
-Os はモジュールを静的型モードでコンパイルし、値ごとの実行時型タグと型スタックを除去します(バイトコードに LCVM_LCBC_FLAG_STATIC_TYPES フラグが付く)。実行時型情報と引き換えに、スループットがおよそ倍増し、スタック使用量が減ります。
このモードは整数とポインタの制御コードを対象とします。浮動小数点(float / double)はこのモードが除去する型情報に依存するため、-Os モジュールは整数とポインタに限定すべきです。printf などの組込み関数は通常(非 -Os)モードで動作し続けます。
lcvmc -Os -oc output.lcbc source.c # 静的型モードでコンパイル
lcvmc -rcn output.lcbc # コンパクトバイトコードを実行
ベンチマークと技術的背景は アーキテクチャ を参照してください。
実装上限
| 項目 | 上限 | 設定箇所 |
|---|---|---|
| スタックサイズ | 100 KB | STACKSIZE |
| グローバル領域 | 100 KB | GLOBALSIZE |
| 管理ヒープ | 256 KB | LCVM_HEAP_MAX |
| VM 再入 / ネスト深度 | 8 | LCVM_MAX_VM_DEPTH |
| 登録 FFI 関数 | 64 | LCVM_FFI_MAX_FUNCTIONS |
| VM レジスタ | 13 | REGSIZE |
| 識別子長 | 30 | IDSIZE |
| 文字列 / トークンバッファ | 2000 | STRSIZE |
| 配列次元数 | 6 | ARR_MAX |
| 関数パラメータ | 無制限 | スタック制限 |
ローダーはさらに、構造的な上限を超えるバイトコードを拒否します: 命令 65536、定数 4096、文字列テーブルとグローバル領域それぞれ 256 KB。
個別機能に関する注記
集約初期化
スカラと文字列の初期化は動作します。構造体・配列の初期化子リストは部分的にしかサポートされません。フィールドごとの代入を推奨し、配列初期化子リストはグローバルに限定してください。
struct Point p; p.x = 10; p.y = 20; /* 推奨 */
char str[] = "hello"; /* OK */
int arr[] = { 1, 2, 3 }; /* グローバルスコープで OK */文字列リテラル
隣接する文字列リテラルは連結されます:
char *s = "hello" "world"; /* "helloworld" */可変長配列
VLA は非対応です。配列サイズはコンパイル時定数でなければなりません。
非対応の言語機能
| 機能 | 理由 |
|---|---|
ビットフィールド(struct { int x:4; }) | 未実装 |
ユーザー定義の可変長引数関数(...) | printf 等は組込みイントリンシック |
複合リテラル((int[]){1,2,3}) | 未実装 |
指示付き初期化子(.x = 1) | 未実装 |
_Bool、inline、restrict、long long | C99 |
フル C プリプロセッサ(#if、関数マクロ …) | プリプロセッサ参照 |
カバレッジ
Lambda C は C89 のおよそ 80% を実装します — 組み込み制御・オーケストレーションスクリプトに十分な範囲 — そして残りは意図的に省きます: クロージャなし、GC なし、動的型付けなし、例外なし。その「なさ」こそが、ランタイムを ROM 配備に十分小さく、ハードリアルタイム制御ループに十分予測可能に保ちます。