การเพิ่ม C99 ของva_copy
API อาร์กิวเมนต์ variadic อาจให้เราเป็นประตูสู่ความสำเร็จของทัวริง เนื่องจากเป็นไปได้ที่จะวนซ้ำผ่านรายการอาร์กิวเมนต์ variadic มากกว่าหนึ่งครั้งในฟังก์ชันอื่นที่ไม่ใช่อาร์กิวเมนต์ที่ได้รับอาร์กิวเมนต์va_args
ตั้งแต่แรก
แน่นอนการใช้งานจริงของอาร์กิวเมนต์ variadic API อาจจะมีตัวชี้อยู่ที่ไหนสักแห่ง แต่ในเครื่องนามธรรมของเรามันสามารถนำมาใช้โดยใช้เวทมนตร์แทน
ต่อไปนี้เป็นตัวอย่างการใช้งานหุ่นยนต์แบบกดลง 2 สแต็กพร้อมกฎการเปลี่ยนแปลงโดยพลการ:
#include <stdarg.h>
typedef struct { va_list va; } wrapped_stack; // Struct wrapper needed if va_list is an array type.
#define NUM_SYMBOLS /* ... */
#define NUM_STATES /* ... */
typedef enum { NOP, POP1, POP2, PUSH1, PUSH2 } operation_type;
typedef struct { int next_state; operation_type optype; int opsymbol; } transition;
transition transition_table[NUM_STATES][NUM_SYMBOLS][NUM_SYMBOLS] = { /* ... */ };
void step(int state, va_list stack1, va_list stack2);
void push1(va_list stack2, int next_state, ...) {
va_list stack1;
va_start(stack1, next_state);
step(next_state, stack1, stack2);
}
void push2(va_list stack1, int next_state, ...) {
va_list stack2;
va_start(stack2, next_state);
step(next_state, stack1, stack2);
}
void step(int state, va_list stack1, va_list stack2) {
va_list stack1_copy, stack2_copy;
va_copy(stack1_copy, stack1); va_copy(stack2_copy, stack2);
int symbol1 = va_arg(stack1_copy, int), symbol2 = va_arg(stack2_copy, int);
transition tr = transition_table[state][symbol1][symbol2];
wrapped_stack ws;
switch(tr.optype) {
case NOP: step(tr.next_state, stack1, stack2);
// Note: attempting to pop the stack's bottom value results in undefined behavior.
case POP1: ws = va_arg(stack1_copy, wrapped_stack); step(tr.next_state, ws.va, stack2);
case POP2: ws = va_arg(stack2_copy, wrapped_stack); step(tr.next_state, stack1, ws.va);
case PUSH1: va_copy(ws.va, stack1); push1(stack2, tr.next_state, tr.opsymbol, ws);
case PUSH2: va_copy(ws.va, stack2); push2(stack1, tr.next_state, tr.opsymbol, ws);
}
}
void start_helper1(va_list stack1, int dummy, ...) {
va_list stack2;
va_start(stack2, dummy);
step(0, stack1, stack2);
}
void start_helper0(int dummy, ...) {
va_list stack1;
va_start(stack1, dummy);
start_helper1(stack1, 0, 0);
}
// Begin execution in state 0 with each stack initialized to {0}
void start() {
start_helper0(0, 0);
}
หมายเหตุ: ถ้าva_list
เป็นประเภทอาเรย์ก็จะมีพารามิเตอร์พอยน์เตอร์ที่ซ่อนอยู่ในฟังก์ชั่น ดังนั้นมันอาจจะดีกว่าการเปลี่ยนประเภทของทุกข้อโต้แย้งva_list
wrapped_stack