Friday, October 2, 2015

Ստրուկտուրաներ TCL լեզվի համար

Կուրսային աշխատանքի նախագիծ։

Այս գրառման մեջ ես ուզում եմ TCL լեզվի օրինակով ցույց տալ, թե ինչպես կարելի է ընդլայնել ծրագրավորվող ծրագրավորման լեզուն, և այն ընդլայնումն էլ ուզում եմ ցույց տալ ստրուկտուրաների օրինակով։ Գաղափարները ես փոխառել եմ Common Lisp լեզվից։

Գիտեմ (իհարկե, որոշ վերապահումներով), որ TCL լեզվում բացակայում են ստրուկտուրաների (գրառումների) հետ աշխատելու գործիքները, և TLC լեզվում առկա են ցուցակ և տող տիպերը և դրանց հետ աշխատելու ֆունկցիաները։ Ես պետք է «ստրուկտուրա» (struct, record) և «նմուշ» (instance) գաղափարներն արտապատկերեմ «ցուցակ» (list), միգուցե նաև «տող» (string) գաղափարներին։

Եթե, օրինակ, արդեն սահմանել եմ person (անձ) ստրուկտուրան, ապա 42 տարեկան Վչոյին նկարագրող նմուշը կարող է ունենալ հետևյալ տեսքը։

{person name Վչո age 42}

Այստեղ երևում է, որ person ստրուկտուրայի նմուշը ներկայացված է մի ցուցակով, որի առաջին տարրը ստրուկտուրայի անունն է, իսկ հաջորդ տարրերը կազմում են սլոտ֊արժեք զույգերի հաջորդականություն։ Նմուշի այսպիսի ներկայացման դեպքում, կարծում եմ, արդեն դժվար չէ սահմանել այն գործիքները, որոնցով աշխատելու եմ ստրուկտուրաների ու դրանց նմուշների հետ։

Քանի որ TCL լեզվում ծրագրի կառուցման բլոկը (շինանյութը) պրոցեդուրան է, ապա ստրուկտուրաների և դրանց նմուշների հետ աշխատելու համար պետք է ունենալ ա) ստրուկտուրա սահմանող, բ) ստրուկտուրայի նմուշ ստեղծող, գ) ստրուկտուրայի դաշտերի (սլոտների) արժեքներ կարդացող և փոփոխող պրոցեդուրաներ։

Օգտագործելով person ստրուկտուրայի օրինակը, սկսեմ սահմանել այդ թվարկված պրոցեդուրաները։ Բայց, առաջ անցնելով ենթադրեմ, թե արդեն սահմանված է struct պրոցեդուրան, որը կատարման միջավայրում սահմանում է նոր ստրուկտուրա։ Դրա օգնությամբ սահմանեմ person ստրուկտուրան։

struct person { name gender age }

Թող create_person պրոցեդուրան վերադարձնում է person ստրուկտուրայի չարժեքավորված նմուշ (կոնստրուկտոր պրոցեդուրա է)։

proc create_person {} {
    list person name {} age {}
}

Վարժություն 1։ Սահմանել create_person պրոցեդուրայի մի այլ տարբերակ, որն արգումենտում ստանում է սլոտների սկզբնական արժեքները և ստեղծում է person ստրուկտուրայի արժեքավորված նմուշ։

Այնուհետև, թող person_name պրոցեդուրան արգումենտում ստանում է person նմուշը և վերադարձնում է դրա name սլոտի արժեքը։

proc person_name { inst } {
    set ps [lsearch $inst name]
    lindex $inst [expr {$ps + 1}]
}

person_name֊ին ստիմետրիկ սահմանեմ նաև person_name_set պրոցեդուրան, որը նմուշի name սլոտին վերագրում է նոր արժեք։

proc person_name_set { inst val } {
 upvar $inst obj
 set ps [lsearch $obj name]
 lset obj [expr {$ps + 1}] $val
}

Վարժություն 2։ Ձևափոխել person_name և person_name_set պրոցեդուրաներն այնպես, որ այն ստուգի, թե արդյո՞ք inst֊ը person-ի նմուշ է։

Վարժություն 3։ Սահմանել նաև age սլոտի արժեքը գրող և կարդացող պրոցեդուրաները։

Հիմա վերադառնամ բուն ստրուկտուրան սահմանող struct պրոցեդուրային։ Արդեն պարզ է, որ s0, s1,... sk սլոտներն ունեցող S ստրուկտուրան սահմանել, նշանակում է կատարման միջավայր ներմուծել create_S կոնստրուկտորը, իսկ ամեն մի si սլոտի համար՝ S_si և S_si_set անունով պրոցեդուրաները։ Այլ կերպ ասած, ստրուկտուրաներ սահմանող struct պրոցեդուրան ամեն մի նոր ստրուկտուրայի համար պետք է սահմանի դրա կոնստրուկտոր և սլոտներին դիմող պրոցեեդուրաները, ինչպես նաև նմուշի տիպը հաստատող պրեդիկատ պրոցեդուրան։ Ահա այն․

proc struct { name slots } {
 set slpatt [list $name]
 foreach sl $slots {
  uplevel "proc ${name}_${sl} \{ inst \} \{
          set ps \[lsearch \$inst $sl]
          lindex \$inst \[expr \{\$ps + 1\}\] \}"

  uplevel "proc ${name}_${sl}_set \{ inst val \} \{
          upvar \$inst obj
          set ps \[lsearch \$obj $sl\]
          lset obj \[expr \{\$ps + 1\}\] \$val \}"

  lappend slpatt $sl {}
 }

 uplevel "proc create_$name \{\} \{ list $slpatt \}"

 uplevel "proc is_$name \{ inst \} \{
      string equal $name \[lindex \$inst 0 0\] \}"
}

Չնայած նրա մի քիչ խճճված տեսքին, տրամաբանությունը բավականին պարզ է։ Այն սահմանում է վերը պահանջված պրոցեդուրաները։

Վարժություն 4։ Ստրուկտուրաների սահմանման, դրանց նմուշների ու սլոտների հետ աշխատող պրոցեդուրաները լրացնել (ընդլայնել) սխալների ստուգման մեխանիզմով։