الأوامر المضمنة:
subst arg
set var ?val?
while cond loop
if cond branch ?cond? ?branch? ?other?
proc name args body
return
break
continue
+, -, *, /, <, >, <=, >=, ==, !=
struct tcl tcl ;
const char * s = "set x 4; puts [+ [* $x 10] 2]" ;
tcl_init ( & tcl );
if ( tcl_eval ( & tcl , s , strlen ( s )) != FERROR ) {
printf ( "%.*sn" , tcl_length ( tcl . result ), tcl_string ( tcl . result ));
}
tcl_destroy ( & tcl );
يتكون برنامج Tcl النصي من أوامر مفصولة بفواصل منقوطة أو رموز سطر جديد. تتكون الأوامر بدورها من كلمات مفصولة بمسافات بيضاء. لجعل المسافة البيضاء جزءًا من الكلمة، يمكن استخدام علامات الاقتباس المزدوجة أو الأقواس.
جزء مهم من اللغة هو استبدال الأوامر ، عندما يتم إرجاع نتيجة الأمر داخل الأقواس المربعة كجزء من الأمر الخارجي، على سبيل المثال puts [+ 1 2]
.
نوع البيانات الوحيد للغة هو سلسلة. على الرغم من أن ذلك قد يؤدي إلى تعقيد العمليات الحسابية، إلا أنه يفتح طريقًا واسعًا لإنشاء خطوط DSL الخاصة بك لتحسين اللغة.
يمكن أن يكون أي رمز جزءًا من الكلمة، باستثناء الرموز الخاصة التالية:
r
أو n
أو الفاصلة المنقوطة أو EOF - تستخدم لتحديد الأوامريحتوي Partcl على وظائف مساعدة خاصة لفئات char هذه:
static int tcl_is_space(char c);
static int tcl_is_end(char c);
static int tcl_is_special(char c, int q);
يتصرف tcl_is_special
بشكل مختلف اعتمادًا على وضع الاقتباس (المعلمة q
). داخل الأقواس المقتبسة، تفقد رموز الفاصلة المنقوطة ورموز نهاية السطر معناها الخاص وتصبح أحرفًا عادية قابلة للطباعة.
يتم تنفيذ Partcl lexer في وظيفة واحدة:
int tcl_next(const char *s, size_t n, const char **from, const char **to, int *q);
تبحث الدالة tcl_next
عن الرمز المميز التالي في السلسلة s
. from
to
يتم تعيينهما للإشارة إلى بداية/نهاية الرمز المميز، يشير q
إلى وضع الاقتباس ويتم تغييره إذا تم استيفاء "
.
يمكن استخدام ماكرو خاص tcl_each(s, len, skip_error)
للتكرار على جميع الرموز المميزة في السلسلة. إذا كانت skip_error
خطأ - تنتهي الحلقة عند انتهاء السلسلة، وإلا فيمكن أن تنتهي الحلقة مبكرًا إذا تم العثور على خطأ في بناء الجملة. فهو يسمح "بالتحقق من صحة" سلسلة الإدخال دون تقييمها واكتشاف وقت قراءة الأمر الكامل.
يستخدم Tcl السلاسل كنوع بيانات أساسي. عندما يتم تقييم البرنامج النصي Tcl، يتم إنشاء العديد من السلاسل أو التخلص منها أو تعديلها. في الأنظمة المدمجة، يمكن أن تكون إدارة الذاكرة معقدة، لذلك يتم نقل جميع العمليات باستخدام قيم Tcl إلى وظائف معزولة يمكن إعادة كتابتها بسهولة لتحسين أجزاء معينة (على سبيل المثال لاستخدام مجموعة من السلاسل، أو مخصص الذاكرة المخصص، أو ذاكرة التخزين المؤقت الرقمية أو قيم القائمة لزيادة الأداء الخ).
/* Raw string values */
tcl_value_t *tcl_alloc(const char *s, size_t len);
tcl_value_t *tcl_dup(tcl_value_t *v);
tcl_value_t *tcl_append(tcl_value_t *v, tcl_value_t *tail);
int tcl_length(tcl_value_t *v);
void tcl_free(tcl_value_t *v);
/* Helpers to access raw string or numeric value */
int tcl_int(tcl_value_t *v);
const char *tcl_string(tcl_value_t *v);
/* List values */
tcl_value_t *tcl_list_alloc();
tcl_value_t *tcl_list_append(tcl_value_t *v, tcl_value_t *tail);
tcl_value_t *tcl_list_at(tcl_value_t *v, int index);
int tcl_list_length(tcl_value_t *v);
void tcl_list_free(tcl_value_t *v);
ضع في اعتبارك أن الدالات ..._append()
يجب أن تحرر الوسيطة الخلفية. أيضًا، السلسلة التي يتم إرجاعها بواسطة tcl_string()
ليس من المفترض أن يتم تحويلها أو تخزينها مؤقتًا.
في قوائم التنفيذ الافتراضية، يتم تنفيذها كسلاسل أولية تضيف بعض عناصر الهروب (الأقواس) حول كل تكرار. إنه حل بسيط يعمل أيضًا على تقليل الكود، ولكن في بعض الحالات الغريبة قد يصبح الهروب خاطئًا وسيتم إرجاع نتائج غير صالحة.
يتم استخدام نوع خاص هو struct tcl_env
للحفاظ على بيئة التقييم (مجموعة من الوظائف). يقوم المترجم بإنشاء بيئة جديدة لكل إجراء محدد من قبل المستخدم، كما توجد بيئة عامة واحدة لكل مترجم.
لا يوجد سوى 3 وظائف تتعلق بالبيئة. أحدهما يخلق بيئة جديدة، والآخر يبحث عن متغير (أو يخلق متغيرًا جديدًا)، والأخير يدمر البيئة وكل متغيراتها.
تستخدم هذه الوظائف malloc/free، ولكن يمكن إعادة كتابتها بسهولة لاستخدام تجمعات الذاكرة بدلاً من ذلك.
static struct tcl_env *tcl_env_alloc(struct tcl_env *parent);
static struct tcl_var *tcl_env_var(struct tcl_env *env, tcl_value_t *name);
static struct tcl_env *tcl_env_free(struct tcl_env *env);
يتم تنفيذ المتغيرات كقائمة مرتبطة واحدة، كل متغير عبارة عن زوج من القيم (الاسم + القيمة) ومؤشر للمتغير التالي.
مترجم Partcl عبارة عن بنية بسيطة struct tcl
تحافظ على البيئة الحالية ومجموعة من الأوامر المتاحة وقيمة النتيجة النهائية.
يتم لف منطق المترجم الفوري حول وظيفتين - التقييم والاستبدال.
الاستبدال:
$
- قم بإنشاء أمر مؤقت [set name]
وقم بتقييمه. في Tcl $foo
هو مجرد اختصار لـ [set foo]
، والذي يُرجع قيمة المتغير "foo" في البيئة الحالية.[
- قم بتقييم ما يوجد داخل الأقواس المربعة وإرجاع النتيجة.{foo bar}
) - قم بإعادتها كما هي، فقط بدون الأقواس.تقييم:
TCMD
لهم) - فابحث عن أمر مناسب (الكلمة الأولى في القائمة) واتصل به. من أين تؤخذ الأوامر؟ في البداية، يبدأ برنامج Partcl interpeter بدون أي أوامر، ولكن يمكن للمرء إضافة الأوامر عن طريق استدعاء tcl_register()
.
كل أمر له اسم، arity (عدد الوسائط التي يجب أن يستغرقها - يتحقق المترجم من ذلك قبل استدعاء الأمر، استخدم arity صفر لـ varargs) ومؤشر دالة C الذي ينفذ الأمر بالفعل.
"set" - tcl_cmd_set
، يعين قيمة للمتغير (إن وجد) ويعيد قيمة المتغير الحالي.
"subst" - tcl_cmd_subst
، يقوم باستبدال الأوامر في سلسلة الوسيطة.
"puts" - tcl_cmd_puts
، يطبع الوسيطة إلى stdout، متبوعة بسطر جديد. يمكن تعطيل هذا الأمر باستخدام #define TCL_DISABLE_PUTS
، وهو مفيد للأنظمة المدمجة التي لا تحتوي على "stdout".
يقوم "proc" - tcl_cmd_proc
، بإنشاء أمر جديد بإلحاقه بقائمة أوامر المترجم الفوري الحالية. هذه هي الطريقة التي يتم بها بناء الأوامر المحددة من قبل المستخدم.
"if" - tcl_cmd_if
، يقوم بإجراء بسيط if {cond} {then} {cond2} {then2} {else}
.
"while" - tcl_cmd_while
، يقوم بتشغيل حلقة while while {cond} {body}
. يمكن للمرء استخدام "استراحة" أو "متابعة" أو "رجوع" داخل الحلقة للتحكم في التدفق.
يتم تنفيذ عمليات رياضية مختلفة كـ tcl_cmd_math
، ولكن يمكن تعطيلها أيضًا إذا لم يكن البرنامج النصي الخاص بك بحاجة إليها (إذا كنت تريد استخدام Partcl كواجهة أوامر، وليس كلغة برمجة).
جميع المصادر في ملف واحد tcl.c
. يمكن استخدامه كمترجم مستقل، أو تضمينه كمكتبة ملف واحد (قد ترغب في إعادة تسميته إلى tcl.h بعد ذلك).
يتم إجراء الاختبارات مع رنة ويتم حساب التغطية. ما عليك سوى تشغيل "إجراء اختبار" وستكون قد انتهيت.
يتم تنسيق التعليمات البرمجية باستخدام تنسيق clang للحفاظ على نمط الترميز النظيف والقابل للقراءة. يرجى تشغيله لطلبات السحب أيضًا.
يتم توزيع الكود بموجب ترخيص MIT، فلا تتردد في استخدامه في مشاريعك الخاصة أيضًا.