- Ang isang abstract syntax tree (AST) ay kumakatawan sa lohikal na istruktura ng isang programa, na nag-aalis ng mga hindi kaugnay na detalye ng sintaksis.
- Ang mga AST ay binuo mula sa mga alpabeto na may mga arity function at tree grammar na tumutukoy kung aling mga node at istruktura ang balido.
- Ang mga notasyon at operator ni Dewey tulad ng "." o "/" ay nagbibigay-daan sa tumpak na pagtukoy sa mga subtree at path sa loob ng mga istrukturang ito.
- Ang mga compiler, interpreter, at mga tool sa pagsusuri ng code ay umaasa sa AST upang mapagkakatiwalaang i-optimize, baguhin, at unawain ang mga programa.

Ang mga abstract syntax tree sa programming ay isa sa mga konseptong sa una ay tila teoretikal, ngunit kapag nasanay ka na sa mga ito, mapagtatanto mo na nasa lahat ng dako ang mga ito: mga compiler, interpreter , code analysis, mga refactoring tool, kahit na sa mga structured data query language. Ang mga ito, sa esensya, ang paraan ng isang makina na "nauunawaan" ang istruktura ng isang programa na lampas sa plain text.
Bagama't minsan ay nalilito sa mga klasikong parse tree, ang mga abstract syntax tree (AST) ay may sariling mga patakaran. Ang isang abstract syntax tree ay hindi lamang isang magandang guhit: ito ay isang siksik at mahusay na dinisenyong istruktura ng datos na nag-aalis ng lahat ng kalabisan mula sa konkretong syntax (mga panaklong, kuwit, paulit-ulit na mga keyword, atbp.) at nakatuon sa mga mahahalaga: kung anong mga operasyon ang isinasagawa, sa anong mga halaga, at sa anong pagkakasunud-sunod.
Ano nga ba ang isang abstract syntax tree (AST)?
Sa teorya ng programming language, ang abstract syntax tree (AST) ay isang mala-tree na istruktura na kumakatawan sa syntax ng isang programa, ngunit sa isang pinasimpleng anyo kumpara sa isang konkretong parse tree. Naglalaman ito ng parehong mahahalagang impormasyon gaya ng parse tree, ngunit nakaayos sa isang mas siksik at mas madaling pamahalaang paraan.
Ang isang parse tree ay naglalaman ng lahat ng mga ginawa ng gramatika at lahat ng mga simbolong terminal, kabilang ang mga panaklong, kuwit, tuldok-kuwit, at iba pang mga elementong purong sintaktika. Sa kabilang banda, inaalis ng AST ang mga detalyeng ito na hindi nag-aambag ng semantikong kahulugan at pinapanatili lamang ang lohikal na istruktura ng mga ekspresyon at pangungusap.
Sa usapin ng implementasyon, ang isang AST ay karaniwang binubuo ng mga node object na may uri na nagpapahiwatig kung anong uri ng syntactic construct ito (constant, identifier, function application, binary operator, atbp.), at mga karagdagang katangian na naglalarawan sa nilalaman nito: value, name, children, argument list, at iba pa.
Ang kagandahan ng AST ay pinapadali nito ang mga susunod na yugto ng compiler o interpreter, tulad ng type checking, optimizations o code generation , dahil nag-aalok ito ng malinis na pagtingin sa istruktura ng programa nang walang syntactic noise.
Pagkakaiba sa pagitan ng isang konkretong puno ng syntax at isang abstract na puno ng syntax
Para lubos na maunawaan kung ano ang naiaambag ng isang AST, makakatulong munang ihambing ang konkretong parse tree sa abstraktong parse tree. Isipin ang isang simpleng gramatika na kumikilala sa mga arithmetic expression tulad ng "a + 4 * 5" . Ang konkretong parse tree ay tumpak na sumasalamin sa aplikasyon ng bawat tuntunin sa gramatika: mga simbolong hindi terminal, terminal, panaklong, operator, atbp.
Ang partikular na punong ito ay karaniwang malalim at may maraming intermediate nodes na nagsisilbi lamang upang mapanatili ang pormal na istruktura ng gramatika. Halimbawa, maaaring may mga node para sa "Expression," "Term," "Factor," at pagkatapos ay mga terminal na simbolo tulad ng "+" , "*" , mga identifier, at mga numero. Ang bawat produksyon ay nagiging isang sangay ng puno, na nagpapataas ng structural complexity.
Ang abstract syntax tree para sa parehong ekspresyon, sa kabilang banda, ay limitado sa kumakatawan sa mga aktwal na operasyon at operand . Kaya, sa halip na ilang antas ng "Expression" at "Term", maaari tayong magkaroon ng root node na kumakatawan sa addition, na may dalawang child: sa kaliwa ay isang identifier na a at sa kanan ay isang multiplication node na ang mga child ay ang mga value na 4 at 5. Ang mga purong grammatical node ay nawawala at ang mga bahagi ng istruktura ay muling inayos o pinaikli.
Nangangahulugan ito na ang AST at ang konkretong syntax tree ay naglalaman ng parehong semantikong impormasyon , ngunit ang una ay nagpapakita nito sa mas direkta at siksik na anyo. Ang kondensasyong ito ay susi sa mahusay na paggamit ng code sa mga tool sa pagsusuri o pagpapatupad.
Mga puno at alpabeto na may arity function
Upang gawing pormal ang mga punong ito mula sa isang matematikal na pananaw, ang ideya ng isang alpabeto na may arity function ay karaniwang ginagamit . Sa halip na isang hanay lamang ng mga simbolo, ang isang alpabeto ay binibigyang kahulugan kung saan ang bawat simbolo ay iniuugnay sa isang numero na nagpapahiwatig kung gaano karaming mga anak ang maaari nitong magkaroon sa puno.
Ang isang alpabeto na may arity function ay, sa impormal na paraan, isang pares na binubuo ng isang may hangganang hanay ng mga simbolo at isang function na nagtatalaga sa bawat simbolo ng isang natural na numero (kabilang ang zero). Ang numerong ito ay nagpapahiwatig ng arity ng simbolo: kung ito ay 0, ang simbolo ay kumikilos bilang isang dahon; kung ito ay 1, ito ay kumikilos bilang isang unary node; kung ito ay 2, ito ay binary; at iba pa. Karaniwan din na payagan ang mga simbolo ng variable arity para sa mga operator bilang mga listahan ng argumento.
Ang mga simbolo ng arity 0 ay tumutugma sa mga dahon ng puno (halimbawa, mga constant o identifier). Ang mga simbolo ng arity 1 ay ginagamit para sa mga construct na may kasamang single child expression. Ang mga simbolo ng arity 2 ay kumakatawan sa mga klasikong binary operation tulad ng pagdaragdag, pagpaparami, pagtatalaga, atbp. At ang mga simbolo ng variable na arity ay nagbibigay-daan sa pagmomodelo ng mga construct na tumatanggap ng hindi tiyak na bilang ng mga subtree, tulad ng isang function call na may maraming parameter.
Mula sa alpabetong ito na may arity, ang hanay ng lahat ng posibleng puno ay maaaring tukuyin: simula sa walang laman na puno (kapag isinaalang-alang), pagdaragdag ng lahat ng simbolo ng arity 0 at variable, at pagpapalawak nang induktibo: kung ang isang simbolo ay k-ary, maaari itong ilagay bilang magulang na node ng k na nabuo nang mga subtree. Nagbubunga ito ng wika (o termino) ng puno na nauugnay sa alpabeto.
Wika ng puno at ang konsepto ng isang node
Ang hanay ng lahat ng mga puno na nabuo gamit ang isang alpabeto at ang arity function nito ay tinatawag, sa kontekstong ito, na isang tree language o terms language . Ito ang katumbas, ngunit para sa mga istruktura ng puno, ng kung ano ang Kleene closure para sa mga string.
Tulad ng kapag sinusuri ang mga string, ginagamit natin ang terminong token upang tukuyin ang mga paglitaw ng mga simbolo ng alpabeto sa loob ng isang sequence, kapag nagtatrabaho sa mga tree, karaniwan nating ginagamit ang terminong node . Ang node ay, sa esensya, isang partikular na paglitaw ng isang simbolo ng alpabeto na may arity na matatagpuan sa isang partikular na posisyon sa tree.
Mula sa pananaw na ito, ang wikang ito ng puno ay para sa mga node kung paanong ang isang hanay ng mga string ay para sa mga token na pangyayari. Ang bawat puno ay binibigyang-kahulugan bilang isang istrukturang binuo nang paunti-unti mula sa alpabeto, at ang mga node ay ang mga indibidwal na piraso na pisikal na nagpapakita ng mga simbolo nito.
Ang ganitong paraan ng pagtingin dito ay lubhang kapaki-pakinabang kapag nagdidisenyo ng mga parser at AST generator , dahil pinapayagan nito ang pangangatwiran tungkol sa mga patakaran sa konstruksyon ng mga punong ito sa paraang kahalintulad ng string grammar, ngunit direktang nagtatrabaho sa mga hierarchical na istruktura.
Arity ng mga node sa isang partikular na AST: ang kaso ng Egg
Mula sa teorya patungo sa praktikal na halimbawa, maraming kagamitan sa pagtuturo ang gumagamit ng wikang Egg upang ilarawan ang pagbuo at manipulasyon ng mga AST. Sa kontekstong ito, ginagamit ang ilang pangunahing uri ng mga node, bawat isa ay may mahusay na natukoy na arity , na ginagawang napakadaling manipulahin ang mga ito.
Sa isang tipikal na Egg AST, ang mga VALUE node ay itinuturing na mga leaf: kinakatawan nila ang mga literal tulad ng mga string o numero. Wala silang mga anak; nag-iimbak lamang sila ng isang halaga. Katulad nito, ang mga WORD node , na ginagamit para sa mga identifier (mga pangalan ng variable, mga pangalan ng function, atbp.), ay itinuturing din bilang mga leaf na may isang property na nag-iimbak ng pangalan.
Ang pangunahing node sa Egg ay ang uri ng APPLY , na kumakatawan sa aplikasyon ng isang function o operator. Ang uri ng node na ito ay may dalawang konseptwal na anak: isang anak na OPERATOR na tumuturo sa ekspresyong inilalapat; at isang anak na ARGS , na sa katunayan ay isang espesyal na ARRAY node na responsable sa pagpapanatili ng isang koleksyon ng mga subtree, isa para sa bawat argumento.
Samakatuwid, ang mga array ay isang natural na paraan upang ipakilala ang variable na arity sa AST: ang isang APPLY ay laging may dalawang bahagi (operator at listahan ng argumento), ngunit ang panloob na listahang iyon ay maaaring maglaman ng zero, isa, o maraming subtree depende sa partikular na tawag na kinakatawan.
Detalyadong anatomiya ng mga AST node sa Egg
Sa antas ng implementasyon, ang mga AST node ng Egg ay karaniwang kinakatawan bilang mga object na may mga property , na perpektong akma sa mga wikang tulad ng JavaScript. Lahat ng node ay may iisang property: `type` , na tumutukoy sa uri ng node (VALUE, WORD, APPLY, ARRAY, atbp.) at, samakatuwid, ang istrukturang magkakaroon ng iba pang bahagi ng object.
Ang mga VALUE node ay ginagamit para sa mga literal na constant . Naglalaman ang mga ito ng isang property, na kadalasang tinatawag na value , kung saan nakaimbak ang numero o string na kinakatawan ng mga ito. Wala silang karagdagang mga anak dahil ang kanilang nilalaman ay ganap na inilalarawan ng literal na iyon.
Ang mga word node ay nakalaan para sa mga identifier : mga pangalan ng variable, pangalan ng function, pangalan ng parameter, at iba pa. Karaniwan silang mayroong katangiang `name` na nag-iimbak ng identifier bilang isang string. Katulad ng mga VALUE node, gumaganap sila bilang mga dahon sa tree, dahil ang kanilang tanging layunin ay ibigay ang pangalang iyon.
Ang mga Apply node ay kumakatawan sa mga aplikasyon o tawag. Kabilang dito ang isang operator property , na tumuturo sa expression (isa pang node) na inilalapat, at isang args property , na nagli-link sa isang ARRAY node. Ang huli ay isang partikular na node sa loob ng AST, na ang layunin ay hawakan ang listahan ng argumento ng aplikasyon .
Ang ARRAY node ay maaaring maunawaan bilang isang nakabalangkas na lalagyan para sa iba pang mga node, na kumakatawan sa isang pagkakasunod-sunod ng mga subtree. Mula sa isang perspektibo ng arity, nagpapakilala ito ng kakayahang umangkop dahil pinapayagan nito ang mga tawag na walang mga argumento, na may isang argumento, o may maraming argumento sa loob ng parehong pahayag na APPLY, nang hindi kinakailangang baguhin ang kahulugan ng pangunahing uri ng node.
Halimbawa ng AST: simpleng aplikasyon na may isang halaga
Para mailarawan ang lahat ng nabanggit, isipin natin ang representasyon ng isang simpleng instruksyon, tulad ng isang aplikasyon ng isang function X na may iisang argumento 5. Ang AST na nabuo ng parser ay tumutugma sa isang term na binuo gamit ang VALUE, WORD at APPLY nodes , kasunod ng mga panuntunan ng Egg.
Sa konseptwal na antas, magkakaroon tayo ng APPLY node sa root. Ang operator property nito ay magtuturo sa isang WORD node na pinangalanang X, at ang args property nito ay magtuturo sa isang ARRAY node na naglalaman ng iisang elemento: isang VALUE node na may numeric value na 5. Sa ganitong paraan, malinaw na ipinapakita ng istruktura kung sino ang inilalapatan at kung saan ito inilalapat.
Kung gusto nating gawing malinaw ang lahat ng katangian, maaari tayong sumulat ng mas detalyadong notasyon na nagpapakita ng uri, operator, argumento, pangalan, at halaga. Ang mas masinsinang notasyong ito ay lubhang kapaki-pakinabang para sa pag-debug ng parser o para sa pag-unawa kung paano isinasalin ang isang tekstong ekspresyon sa isang tree object sa loob ng interpreter.
Sa mga implementasyon sa totoong mundo, ang punong ito ay karaniwang naka-serialize bilang JSON para sa madaling pag-iimbak, pagpapadala, o pag-inspeksyon. Sa katunayan, ang mga tool at module, tulad ng evm2term package sa npm ecosystem, ay nagbibigay ng mga compact na representasyon ng mga AST na ito para sa mas madaling pagsusuri o pagbabago.
Halimbawa ng AST: nested addition at multiplication
Ang isa pang tipikal na kaso ay isang medyo mas kumplikadong ekspresyon, tulad ng "+(a, *(4, 5))" . Dito mayroon tayong operasyon ng pagdaragdag na ang unang argumento ay ang identifier na a at ang pangalawang argumento ay ang resulta ng pagpaparami ng 4 sa 5. Ang AST na resulta ng ekspresyong ito ay sumasalamin sa nested structure na iyon.
Sa ugat ng puno, magkakaroon muli tayo ng isang APPLY node na kumakatawan sa operasyon ng pagdaragdag. Ang operator nito ay isang WORD node na pinangalanang "+", habang ang mga argumento nito ay nasa isang ARRAY node na may dalawang elemento: ang una, isang WORD na pinangalanang "a"; ang pangalawa, isa pang APPLY node na kumakatawan sa multiplikasyon.
Ang pangalawang APPLY ay magkakaroon bilang operator nito ng isang WORD na pinangalanang "*" at bilang argumento nito ay isang ARRAY na may dalawang VALUE node: ang isa ay may halagang 4 at ang isa naman ay may halagang 5. Sa kabuuan, malinaw na ipinapakita ng istruktura na ang pagkakasunud-sunod ng pagsusuri ay binubuo ng pagpaparami ng 4 sa 5 at pagkatapos ay pagdaragdag ng resulta sa a.
Kung palalawakin natin ang notasyon upang maisama ang lahat ng katangian, makikita natin ang mga uri ng lahat ng node, ang kanilang mga pangalan o mga partikular na halaga, at ang mga ugnayan sa pagitan ng mga ito. Ang tahasang paglalarawan na ito ay tumutugma sa aktwal na implementasyon sa Egg interpreter, kung saan ang bawat node ay isang object na may mga nabanggit na katangian.
Gramatika ng puno at gramatika ng parser
Ang paraan ng pagbuo ng mga AST na ito ay hindi arbitraryo: ito ay batay sa tinatawag na Tree Grammar . Sa isang tipikal na pormulasyon, ang naturang gramatika ay binibigyang kahulugan bilang isang quadruple na binubuo ng isang alpabeto na may arity, isang may hangganang hanay ng mga sintaktik (hindi terminal) na baryabol, isang may hangganang hanay ng mga tuntunin sa produksyon, at isang panimulang simbolo.
Sa bawat tuntunin ng produksyon, ang isang baryabol ay pinapalitan ng isang puno na ang ugat ay simbolo ng alpabeto na may arity, at ang mga anak naman ay mga baryabol o mga punong natukoy na. Ang istrukturang ito ay nakapagpapaalaala sa mga klasikong regular o walang kontekstong gramatika, ngunit inangkop sa direktang pagbuo ng mga puno sa halip na mga hanay ng mga simbolo.
Kaugnay ng mas pormal na kahulugang iyon ay ang partikular na gramatika na ginagamit ng parser ng Egg upang makabuo ng mga tree nito. Ang gramatikang ito, na karaniwang impormal na ipinapakita sa dokumentasyon, ay naglalarawan nang eksakto kung aling mga kumbinasyon ng mga keyword, operator, panaklong, at iba pa ang tinatanggap sa wika at kung paano ito isinasalin sa mga node na may uri na VALUE, WORD, APPLY, at ARRAY.
Ang tree grammar na ito ay maaaring ituring na isang espesyal na kaso ng tinatawag sa literatura bilang Regular Tree Grammar . Ang ideya ay magkaroon ng mahusay na natukoy na mga patakaran para sa pag-convert ng isang pagkakasunod-sunod ng mga input token sa isang nakabalangkas na AST na maaaring bigyang-kahulugan o i-compile.
Notasyon ni Dewey: mga coordinate sa loob ng isang puno
Kapag mayroon na tayong AST, madalas nating kailangan tukuyin ang mga partikular na subtree : halimbawa, ang pangalawang argumento ng isang function, ang operator ng isang expression, atbp. Ang isang napaka-eleganteng paraan upang gawin ito ay ang tinatawag na Dewey Decimal notation, na humiram ng iskemang ginagamit sa pagnunumero ng mga seksyon at subsection sa mga dokumento.
Sa notasyong ito, simula sa isang puno na t, ang isang subtree ay minamarkahan ng isang hanay ng mga numero na pinaghihiwalay ng mga tuldok . Ang bawat numero ay nagpapahiwatig ng posisyon ng isang anak (karaniwang nagsisimula sa 1) at ang pagkakasunod-sunod ay bumababa sa puno. Kaya, ang isang ekspresyon tulad ng t/2.1.3 ay tumutukoy sa ikatlong anak ng unang anak ng pangalawang anak ng t.
Ang induktibong kahulugan ng notasyong ito ay simple: ang walang laman na string ay tumutukoy sa buong puno mismo; kung ang isang string ay binubuo ng isang numero na sinusundan ng higit pang mga numero na pinaghihiwalay ng mga tuldok, ito ay binibigyang-kahulugan sa pamamagitan ng unang pagkuha ng child subtree na naaayon sa ipinahiwatig na index at pagkatapos ay paglalapat ng parehong lohika nang recursively sa natitirang bahagi ng string.
Halimbawa, kung mayroon tayong tree na t na kumakatawan sa isang expression tulad ng "+(a, *(4,5))", na may root node na APPLY para sa addition, isang child WORD na pinangalanang "+", at isa pang child APPLY para sa multiplication, matutukoy natin ang mga partikular na posisyon. Kaya, ang t/1 ay maaaring ang WORD node na may operator na "+", ang t/2.1 ang identifier na "a", at ang t/2.2.2.1 ang VALUE node na may value na 4, kung bibilangan natin ng tamang numero ang mga child.
Ang ganitong paraan ng pagbibigay ng "mga coordinate" sa loob ng isang AST ay lubhang kapaki-pakinabang para sa pagturo ng mga partikular na lokasyon kapag nag-uulat ng mga error, pag-navigate sa tree , o paglalapat ng mga lokal na transformasyon sa mga partikular na node nang walang kalabuan.
Mga katumbas na notasyon sa programming at mga tool
Ang ideya sa likod ng notasyon ni Dewey ay hindi eksklusibo sa teorya ng puno; sa katunayan, paulit-ulit itong lumilitaw sa maraming praktikal na notasyon na ginagamit natin araw-araw sa pagprograma at paghawak ng istrukturang datos, kahit na hindi natin ito laging nalalaman.
Kapag nagsusulat tayo ng mga ekspresyon gamit ang dot operator sa isang programming language , tulad ng object.property.subproperty, ginagawa natin ang isang bagay na halos kapareho: tinatahak ang isang tree ng mga nested object, pumipili ng child sa bawat hakbang ayon sa pangalan sa halip na ayon sa position number. Simula sa isang root node, bumababa tayo patungo sa mas maraming internal nodes.
Ang parehong padron ay lumilitaw sa mga sistema ng file na parang Unix, kung saan ang forward slash operator (/) ay ginagamit upang paghiwalayin ang mga direktoryo: Inilalarawan ng /src/js/tutu.js ang isang landas mula sa ugat ng sistema ng file patungo sa isang partikular na mapagkukunan, na tumatawid sa magkakasunod na antas ng isang istruktura ng puno.
Sa mundo ng mga nakabalangkas na dokumento, ang mga wikang tulad ng XPath ay gumagamit ng halos magkatulad na mga notasyon upang pumili ng mga node sa loob ng isang XML tree. Ang isang query tulad ng "A//B/*" ay pumipili ng unang anak (anuman ang pangalan nito) ng bawat elemento B na isang inapo ng isang elemento A sa naaangkop na posisyon kaugnay ng kasalukuyang konteksto, gamit ang mga single at double slash upang ipahiwatig ang mga antas ng lalim.
Ang isa pang kilalang kagamitan, ang wikang jq , ay gumagamit ng parallel system upang mag-navigate sa mga istruktura ng JSON, na nagpapahintulot sa pagpili ng mga sub-object sa pamamagitan ng mga composite path, filter, at expression. Ang lahat ng mga notasyong ito ay iba't ibang paraan lamang ng pagpapahayag ng mga path sa isang tree , na halos kapareho ng notasyon ni Dewey Decimal ngunit inangkop sa kani-kanilang mga domain.
Pag-parse ng mga puno sa lingguwistika at programming
Bukod sa mundo ng mga compiler, ginagamit din ang mga syntax tree sa lingguwistika upang kumatawan sa istruktura ng pangungusap. Doon, tinatawag ang mga ito na derivation tree o parse tree, na nagpapakita kung paano hinahati ang isang pangungusap sa mga parirala, salita, at mga kategoryang gramatikal.
Sa mga punong ito, tulad ng sa programming, makakakita tayo ng tatlong pangunahing uri ng node: isang root node , na kumakatawan sa kumpletong pangungusap o sa pandaigdigang istruktura; mga internal o branching node, na gumaganap bilang mga parent node at group subset ng pangungusap; at mga leaf node, na karaniwang tumutugma sa mga partikular na salita na lumalabas sa input string.
Ang root node ay natatangi: ang buong istruktura ng puno ay nakasabit dito. Ang mga branching node ay matatagpuan mismo sa ibaba ng root o iba pang parent node, at nagsisilbing hirarkikong ayusin ang mga bahagi ng pangungusap o programa. Ang mga leaf node, sa kabilang banda, ay matatagpuan sa pinakamababang antas ng puno at walang mga anak, kaya isinasara ang branching structure.
Ang mga punong ito ay itinuturing na makapangyarihang kagamitang pedagogical dahil nakakatulong ang mga ito sa paghati-hati ng mga kumplikadong pangungusap sa mga elementong mapapamahalaan. Ganito rin ang naaangkop sa programming: ang isang mahusay na pagkakagawa ng AST ay nagbibigay-daan sa iyong makita sa isang sulyap kung aling mga operasyon ang magkakaugnay, kung aling mga ekspresyon ang nakapatong, at kung paano dumadaloy ang pagsusuri.
Depende sa layunin ng pagsusuri, makakahanap tayo ng iba't ibang uri ng mga puno ng pagsusuri . Ang ilan ay nagbibigay-diin sa mga dependency sa pagitan ng mga salita o mga bahagi (halimbawa, kung sino ang umaasa kanino sa isang pangungusap), habang ang iba ay nakatuon sa pagpapangkat-pangkat sa mga parirala o mga bumubuo, na nagreresulta sa dalawang pangunahing pamilya.
Mga puno ng sintaks ayon sa dependency at ayon sa constituency
Isa sa mga pinakakilalang uri ay ang dependency-based syntax tree . Sa variant na ito, lahat ng salita sa pangungusap o lahat ng kaugnay na elemento ay itinuturing na mga leaf node, at ang mga ugnayan sa pagitan ng mga ito ay nagpapahiwatig ng direktang ugnayan ng dependency (halimbawa, isang pangunahing pandiwa at simuno nito). Bilang resulta, ang mga puno na may mas kaunting node ay kadalasang nalilikha kaysa sa iba pang mga iskema.
Ang pagiging simple na ito ay ginagawang mas maginhawa ang mga ito para sa mga nagsisimula at para sa ilang mga gawain sa pagproseso ng wika, dahil ang istraktura ay nakatuon sa kung sino ang umaasa kanino nang hindi nagpapakilala ng napakaraming intermediate nodes. Kung ilalapat sa programming, ang ideya ay manatili lamang sa mga mahahalagang ugnayan, na inaalis ang mga palamuting gramatikal.
Sa kabilang dulo, mayroon tayong mga syntax tree batay sa mga constituent o constituent, na nagpapaiba sa pagitan ng mga root node, internal branching node, at leaf node, at nagpapakita ng lahat ng kaugnay na grupo. Ang mga punong ito ay karaniwang naglalaman ng mas maraming node at mas detalyadong sumasalamin sa hierarchical na istruktura ng pangungusap o programa.
Ang mga karaniwang nakikitang template ng constituency tree ay nagpapakita ng mahahabang pangungusap na may maraming leaf node, iba't ibang antas ng pagsasanga, at isang mahusay na tinukoy na root node. Ang mga ito ay lalong kapaki-pakinabang para sa pag-dissect ng mga kumplikadong pangungusap o programa na may maraming layer ng nested structures.
Sa parehong dependency at constituency trees, may mga halimbawa at visual resources na makukuha bilang mga template, na nagbibigay-daan sa iyong punan lamang ang mga node ng ninanais na impormasyon. Nakakatipid ito ng oras at naiiwasan ang pagdidisenyo ng diagram mula sa simula sa bawat pagkakataong gusto mong ilarawan ang isang istruktura.
Mga praktikal na aplikasyon at kagamitan na may kaugnayan sa AST
Ang mga AST ay hindi lamang isang teoretikal na konsepto: aktibo ang mga ito na ginagamit sa maraming pang-araw-araw na kagamitan ng sinumang gumagamit ng code. Ang mga compiler, interpreter, minifier, code formatter, at static analyzer ay halos palaging umaasa sa isang AST upang maisagawa ang kanilang tungkulin.
Kinukuha ng isang tipikal na compiler ang source code, itina-tokenize ito, pina-parse ito, at bumubuo ng isang abstract syntax tree. Mula doon, nagsasagawa ito ng mga semantic check (mga uri, variable scope, maling paggamit ng mga construct) at inilalapat ang code optimization sa pamamagitan ng pagtawid at pagbabago ng AST bago gumawa ng machine code, o bytecode.
Ang mga kagamitang tulad ng mga linter o formatter ay gumagana rin sa AST: sinusuri nila ang istruktura upang matukoy ang mga problematikong pattern, masasamang kasanayan o hindi pagkakapare-pareho at nagmumungkahi ng mga pagbabago na nagpapanatili sa semantikong istruktura ng puno ngunit inaayos ang presentasyon ng code.
Halimbawa, sa JavaScript ecosystem, mayroong maraming library na nagpapakita ng AST sa JSON format, na ginagawang mas madali para sa iba pang mga tool na umasa dito upang magsagawa ng refactoring, bumuo ng awtomatikong dokumentasyon, o lumikha ng mga visualization ng istruktura ng mga kumplikadong programa.
Kahit sa medyo mas espesyalisadong mga larangan, tulad ng instrumentasyon para sa pagsukat ng saklaw ng pagsubok o ang pagbabago ng source code sa iba pang mga wika, ang AST ang pundasyon kung saan nakabatay ang maraming modernong solusyon, dahil pinapayagan nito ang pagtatrabaho sa isang napaka-komportableng antas ng abstraksyon sa pagitan ng hilaw na teksto at machine code.
Kung pagsasama-samahin, ang mga abstract syntax tree ang pangunahing piraso na nag-uugnay sa pormal na gramatika ng isang wika, ang panloob na representasyon nito sa compiler o interpreter, at ang mga advanced na tool na ginagamit natin upang magsulat, mag-analisa, at mag-transform ng code nang ligtas at mahusay. Ang pag-unawa kung paano ito binubuo, kung paano gamitin ang mga ito (gamit ang mga konsepto tulad ng Dewey Decimal notation), at kung anong mga uri ng node ang kasangkot (VALUE, WORD, APPLY, fixed o variable arity structures, atbp.) ay nakakatulong sa atin na makita nang mas malinaw kung ano talaga ang ginagawa ng makina kapag pinoproseso nito ang isang programa.

