Apa Hubungan Antara Bahasa Pemrograman, Ekspresi Reguler, dan Bahasa Formal

25

Saya telah mencari-cari jawaban untuk pertanyaan ini dan kelihatannya semua orang secara implisit tahu jawabannya kecuali saya. Agaknya ini karena satu-satunya orang yang peduli adalah mereka yang pernah memiliki pendidikan tinggi tentang hal itu. Saya, di sisi lain, telah dilemparkan ke dalam untuk tugas sekolah menengah.

Pertanyaan saya adalah, bagaimana tepatnya bahasa pemrograman terkait dengan bahasa formal? Di mana-mana saya membaca, sesuatu di sepanjang baris "bahasa formal digunakan untuk mendefinisikan tata bahasa bahasa pemrograman" dikatakan.

Sekarang dari apa yang saya dapat kumpulkan, bahasa formal adalah serangkaian aturan produksi yang berlaku untuk serangkaian simbol tertentu (alfabet bahasa). Aturan produksi ini menentukan serangkaian transformasi, seperti:

b -> a

aaa->c

Ini dapat diterapkan sedemikian rupa sehingga:

abab->aaaa aaaa-> ca

Sama seperti catatan tambahan, jika kita mendefinisikan bahwa alfabet bahasa formal kita sebagai {a, b, c}, maka a dan b adalah bukan terminal dan c adalah terminal karena tidak dapat diubah (perbaiki saya jika saya salah tentang bahwa).

Jadi mengingat semua itu, bagaimana mungkin ini berlaku untuk bahasa pemrograman? Seringkali juga dinyatakan bahwa regex digunakan untuk mengurai bahasa dalam bentuk teks untuk memastikan tata bahasa benar. Ini masuk akal. Kemudian dinyatakan bahwa regex didefinisikan oleh bahasa formal. Regex mengembalikan benar atau salah (setidaknya dalam pengalaman saya) tergantung pada apakah automata keadaan terbatas yang mewakili regex mencapai titik tujuan. Sejauh yang saya bisa lihat, itu tidak ada hubungannya dengan transformasi *.

Untuk mengkompilasi program itu sendiri, saya kira bahasa formal akan dapat mengubah kode menjadi kode tingkat yang lebih rendah secara berurutan, akhirnya mencapai perakitan melalui seperangkat aturan yang kompleks, yang kemudian dapat dipahami oleh perangkat keras.

Jadi itu hal-hal dari sudut pandang saya yang bingung. Mungkin ada banyak hal yang secara fundamental salah dengan apa yang saya katakan, dan itulah sebabnya saya meminta bantuan.


* Kecuali Anda menganggap sesuatu seperti (a|b)*b*c->trueaturan produksi, dalam hal ini aturan tersebut memerlukan automata keadaan terbatas (yaitu: regex). Ini tidak masuk akal karena kami baru saja mengatakan itu

Zwander
sumber
2
Anda mengacaukan tata bahasa formal dengan bahasa formal . Sebuah tata bahasa adalah seperangkat aturan penulisan ulang yang menggambarkan bahasa. Bahasa adalah himpunan string yang dijelaskan oleh tata bahasa. Jadi tata bahasa adalah alternatif untuk ekspresi reguler: itu adalah cara untuk menggambarkan bahasa.
reinierpost
@reinierpost Anda sepenuhnya benar, setelah melihat catatan kuliah di universitas, saya mendapat informasi ini, saya melihat kesalahan saya.
Zwander
Saya berbagi kebingungan Anda ketika saya mulai. Tentu saja, tata bahasa membentuk bahasa juga, dan begitu juga ekspresi reguler. Tetapi teori bahasa formal dikhususkan untuk mempelajari bagaimana sintaks (bentuk) bahasa dapat dijelaskan, sehingga biasanya menggunakan istilah 'bahasa' untuk apa yang dijelaskan, bukan apa yang menggambarkannya.
reinierpost

Jawaban:

24

Siapa pun yang memberi tahu Anda bahwa ekspresi reguler yang digunakan untuk mem-parsing kode menyebarkan disinformasi. Secara klasik (saya tidak tahu sampai sejauh mana ini benar dalam kompiler modern), parsing kode - konversi kode dari teks ke pohon sintaks - terdiri dari dua tahap:

  1. Analisis leksikal: Memproses teks mentah menjadi potongan - potongan seperti kata kunci , konstanta numerik , string , pengidentifikasi dan sebagainya. Ini diimplementasikan secara klasik menggunakan semacam mesin keadaan terbatas, serupa semangatnya dengan robot terbatas deterministik (DFA).

  2. Parser: Jalankan setelah analisis leksikal, dan mengubah teks mentah menjadi pohon sintaksis beranotasi. Tata bahasa bahasa pemrograman (untuk perkiraan pertama) bebas konteks (sebenarnya, seseorang membutuhkan subset yang lebih ketat), dan ini memungkinkan algoritma efisien tertentu untuk mem-parsing kode lexified ke dalam pohon sintaksis. Ini mirip dengan masalah mengenali apakah string yang diberikan milik tata bahasa bebas konteks, perbedaannya adalah bahwa kita juga menginginkan bukti dalam bentuk pohon sintaksis.

Tata bahasa untuk bahasa pemrograman ditulis sebagai tata bahasa bebas konteks, dan representasi ini digunakan oleh generator parser untuk membuat parser cepat untuk mereka. Contoh sederhana akan memiliki beberapa PERNYATAAN non-terminal dan kemudian aturan bentuk PERNYATAAN IF-PERNYATAAN, di mana IF-PERNYATAAN jika KONDISI maka BLOK endif, atau sejenisnya (di mana BLOK PERNYATAAN BLOK; PERNYATAAN, untuk contoh). Biasanya tata bahasa ini ditentukan dalam bentuk Backus-Naur (BNF).

Spesifikasi aktual bahasa pemrograman tidak bebas konteks. Misalnya, variabel tidak dapat muncul jika belum dideklarasikan dalam banyak bahasa, dan bahasa dengan pengetikan yang ketat mungkin tidak memungkinkan Anda untuk menetapkan bilangan bulat ke variabel string. Pekerjaan parser hanya mengubah kode mentah menjadi bentuk yang lebih mudah diproses.

Saya harus menyebutkan bahwa ada pendekatan lain seperti parsing keturunan rekursif yang tidak benar-benar menghasilkan pohon parse, tetapi proses kode Anda saat mem-parsingnya. Meskipun tidak mengganggu untuk menghasilkan pohon, dalam semua hal lain ia beroperasi pada tingkat yang sama seperti yang dijelaskan di atas.

Yuval Filmus
sumber
Terima kasih atas balasan Anda, itu jelas menyelesaikan beberapa hal. Ini juga membawa banyak pertanyaan. Haruskah saya menambahkannya ke pertanyaan saya, atau bertanya di sini?
Zwander
5
@ Zwander - sebenarnya, tidak juga. Di situs ini, kami ingin Anda menulis satu pertanyaan per pertanyaan. Itu bukan forum diskusi: ini adalah situs tanya jawab, dan kami ingin setiap pertanyaan berada di utas terpisah. Jika jawaban ini menimbulkan pertanyaan baru, maka luangkan waktu untuk meneliti pertanyaan tindak lanjut itu, dan jika Anda tidak dapat menemukan jawaban di salah satu sumber standar, posting pertanyaan baru. (Tetapi pastikan untuk melihat sumber daya standar terlebih dahulu.)
DW
1
@DW Gotcha, tepuk tangan.
Zwander
3
Yang pertama dari dua tahap yang Anda sebutkan biasanya dilakukan dengan menggunakan ekspresi reguler. Format setiap token biasanya diberikan oleh ekspresi reguler. Ekspresi reguler tersebut dikompilasi menjadi DFA tunggal, DFA kemudian diterapkan pada kode aktual.
kasperd
2
@Zwander Penguraian keturunan rekursif adalah salah satu teknik penguraian. Mungkin atau mungkin tidak menghasilkan pohon parse. Secara umum, jumlah algoritma penguraian untuk mengembangkan strategi komputasi untuk mengeksplorasi pohon sintaksis tersirat dalam teks program. Sintaks / parse tree ini dapat atau tidak dapat dijelaskan dalam proses, tergantung pada strategi kompilasi (jumlah tahapan). Apa yang diperlukan adalah bahwa pada akhirnya ada setidaknya satu eksplorasi bottom-up dari pohon parse, apakah dieksplisit atau dibiarkan tersirat dalam struktur perhitungan.
babou
12

Ini adalah beberapa hal yang berat untuk tugas sekolah menengah.

Jawaban Yuval Filmus sangat bagus, jadi ini lebih merupakan jawaban tambahan untuk memperjelas beberapa poin yang dia buat.

Bahasa formal adalah konstruksi matematika. Penggunaannya untuk bahasa pemrograman hanyalah salah satu dari banyak kegunaan yang mungkin; pada kenyataannya, ahli bahasa Noam Chomsky membuat kontribusi signifikan pada teori awal bahasa formal. Dia menemukan Hierarki Chomsky, yang mengklasifikasikan bahasa formal ke dalam bahasa reguler, bebas konteks, dll. Bahasa formal juga diterapkan dalam linguistik untuk menggambarkan sintaksis bahasa alami seperti bahasa Inggris. Pikirkan itu seperti bilangan real: kita dapat menggunakan bilangan real untuk menggambarkan kedua hal nyata seperti jarak dari Los Angeles ke New York, dan hal-hal abstrak seperti rasio keliling lingkaran dengan diameternya. Meskipun kedua hal itu ada terlepas dari bilangan real, bilangan real adalah sistem yang membantu untuk menggambarkan mereka. Bahasa formal adalah sistem yang membantu untuk menggambarkan bahasa Inggris dan Python, karena keduanya memiliki format terstruktur yang sama.

Sebuah+b+c=dSebuah+b=d-cSebuahbc sebagai jumlah dolar, misalnya, dan kemudian persamaan memiliki makna.

Secara klasik, bahasa pemrograman akan memiliki dua tata bahasa: tata bahasa leksikal dan tata bahasa sintaksis. Tata bahasa leksikal berkaitan dengan karakter seperti huruf, titik koma, kawat gigi, dan tanda kurung. Ini biasanya tata bahasa biasa, sehingga dapat diekspresikan dengan ekspresi reguler atau DFA atau NFA. (Ada bukti dalam teori bahasa formal yang menunjukkan ketiganya setara dalam kekuasaan — yang berarti mereka menerima serangkaian bahasa yang sama.) Fase pengeksposan dari kompiler atau juru bahasa adalah semacam juru bahasa mini untuk tata bahasa bahasa biasa. Itu membaca aturan tata bahasa, dan mengikuti aturan itu, itu menggumpalkan karakter individu menjadi token. Misalnya, jika bahasa tersebut memiliki ifpernyataan yang kurang lebih mirip dengan C, lexer mungkin menyamakan karakter idan fke dalam token tunggal.IF, kemudian cari tanda kurung buka dan beri tanda token OPEN_PAREN, lalu pegang apa pun yang ada di antara tanda kurung, dan kemudian temukan tanda kurung penutup dan keluaran a CLOSE_PAREN. Ketika lexer selesai membuat token, ia menyerahkannya ke parser, yang menentukan apakah token tersebut benar-benar membentuk pernyataan yang valid dari bahasa pemrograman. Jadi jika Anda menulis ip a == bdengan Python, lexer hanya melakukan yang terbaik untuk menebak token seperti apa ip(mungkin itu akan diambil untuk pengenal oleh kebanyakan lexers), dan meneruskannya ke parser, yang mengeluh karena Anda tidak dapat memiliki pengidentifikasi di posisi itu.

Sebuahb

Mari kita lihat aturan tata bahasa untuk ifpernyataan Python . Ini aturannya:

if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]

Aturan itu memberi tahu kita bagaimana parser akan mencari tahu apakah serangkaian token yang dikirim dari lexer adalah ifpernyataan. Setiap kata dalam tanda kutip tunggal harus muncul, begitu saja, dalam kode sumber, sehingga pengurai akan mencari kata yang sederhana if. Parser kemudian akan mencoba mencocokkan beberapa token dengan aturan untuk test:

test: or_test ['if' or_test 'else' test] | lambdef

testdidefinisikan dalam hal aturan lain dalam tata bahasa. Perhatikan bagaimana testjuga memasukkan dirinya dalam definisinya; itu disebut definisi rekursif. Ini adalah kekuatan besar bahasa bebas konteks yang tidak dimiliki bahasa reguler, dan memungkinkan hal-hal seperti loop bersarang untuk didefinisikan untuk sintaksis bahasa pemrograman.

Jika parser berhasil mencocokkan beberapa token test, ia akan mencoba mencocokkan titik dua. Jika itu berhasil, itu akan mencoba mencocokkan beberapa token lainnya menggunakan aturan untuk suite. Bagian ini ('elif' test ':' suite)*berarti bahwa kita dapat memiliki sejumlah pengulangan teks literal elif, diikuti oleh sesuatu yang cocok test, diikuti oleh titik dua, diikuti oleh sesuatu yang cocok suite. Kami juga dapat memiliki nol pengulangan; tanda bintang pada akhirnya berarti "nol atau sebanyak yang kita inginkan".

Pada akhirnya adalah ['else' ':' suite]. Bagian itu tertutup tanda kurung; itu berarti kita dapat memiliki nol atau satu, tetapi tidak lebih. Untuk mencocokkan ini, parser perlu mencocokkan teks literal else, titik dua, dan kemudian a suite. Inilah aturan untuk suite:

suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT

Ini pada dasarnya adalah blok dalam bahasa C-like. Sejak Python menggunakan baris dan lekukan pada hal-hal yang berarti, output lexer NEWLINE, INDENTdan DEDENTtoken untuk memberitahu parser di mana baris baru dimulai, di mana kode mulai menjorok, dan di mana ia kembali ke tingkat luar lekukan.

Jika salah satu dari upaya pencocokan ini gagal, parser menandai kesalahan dan berhenti. Jika parsing seluruh program berhasil, parser biasanya akan membangun pohon parse seperti Yuval tercakup dalam jawabannya, dan mungkin tabel simbol dan struktur data lain yang menyimpan informasi semantik. Jika bahasa diketik secara statis, kompiler akan memandu pohon parse dan mencari kesalahan ketik. Itu juga berjalan pohon parse untuk menghasilkan kode tingkat rendah (bahasa assembly, bytecode Java, .Net Intermediate Language, atau yang serupa) yang merupakan apa yang sebenarnya berjalan.

Sebagai latihan, saya akan merekomendasikan mengambil tata bahasa dari beberapa bahasa pemrograman yang Anda kenal (sekali lagi, Python , Java , dan inilah C # , Javascript , C ) dan mencoba untuk mengurai sesuatu yang sederhana, seperti mungkin x = a + b;atau if (True): print("Yay!"). Jika Anda mencari sesuatu yang lebih sederhana, ada juga tata bahasa yang bagus untuk JSON , yang pada dasarnya hanya mencakup sintaks untuk objek literal dalam Javascript (seperti {'a': 1, 'b': 2}). Semoga beruntung, ini adalah hal-hal yang membekukan otak tetapi ternyata benar-benar menarik ketika Anda tidak berada di tenggat waktu yang gila.

tsleyson
sumber
Saya tahu saya tidak seharusnya memposting "terima kasih" di sini, tetapi sorak-sorai karena meluangkan waktu untuk menjelaskan semua ini. "Ini barang berat untuk tugas sekolah menengah." Tujuan dari tugas ini adalah untuk membaca skim dari atas dan berbicara tentang ekspresi reguler, tetapi sebagai mahasiswa ilmu komputer yang rajin, saya ingin mendapatkan gambaran keseluruhan. Seluruh topik menarik.
Zwander
1
@ Zwander Saya baru saja lulus kuliah, dan sebagian besar pilihan saya adalah seperti ini. Saya ingat benar-benar bingung tetapi sepenuhnya terserap. Anda mungkin juga menyukai makalah tentang desain kompiler yang disebutkan dalam blog ini , atau buku Pengantar Teori Komputasi , oleh Michael Sipser, dan John C. Martin, Pengantar Bahasa dan Teori Komputasi . Anda dapat menemukan salinan bekas yang murah di Amazon. Keduanya membuat teori bahasa formal sesederhana yang akan didapat.
tsleyson
10

Pendeknya

Bahasa pemrograman terdiri dari sintaks yang mewakili program sebagai string karakter, dan semantik yang merupakan makna yang dimaksud dari program.

Bahasa formal adalah sintaksis tanpa makna. Ini dimaksudkan untuk mempelajari struktur set string yang didefinisikan secara formal, tanpa biasanya menempelkan makna pada string tersebut.

Ekspresi reguler dan formalisme lainnya (seperti Context-Free Grammars) digunakan untuk mendefinisikan bahasa formal, digunakan sebagai komponen sintaksis pemrograman dan bahasa alami, yaitu untuk merepresentasikan kalimat dengan cara terstruktur. Mekanisme lain digunakan untuk menghubungkan struktur itu dengan semantik bahasa pemrograman.

Banyak di sini sangat disederhanakan, terutama mengenai bahasa alami.

Dengan lebih banyak detail

Untuk menjawab pertanyaan Anda, kami harus mulai dari awal. Bahasa dalam arti biasa, secara informal, merupakan sarana untuk menyampaikan informasi atau ide. Dalam suatu bahasa, orang biasanya membedakan antara sintaks dan semantik. Semantik adalah apa yang ingin Anda bicarakan / tulis. informasi yang ingin Anda sampaikan. Sintaks adalah cara yang Anda gunakan untuk menyampaikannya, yaitu representasi konvensional yang dapat dipertukarkan antara orang, dan sekarang juga antara orang dan perangkat, atau antara perangkat (komputer).

Biasanya, Anda akan menggunakan kata itu doguntuk menyampaikan ide tentang seekor anjing. Kata dogitu terbuat dari tiga huruf, atau suara yang setara, dan dimaksudkan untuk menjadi representasi dari beberapa jenis hewan. Gagasan utamanya adalah bahwa komunikasi dilakukan melalui representasi dari apa yang harus dikomunikasikan. Struktur representasi biasanya disebut sintaksis, sedangkan yang direpresentasikan disebut semantik. Ini berlaku lebih atau kurang untuk bahasa alami serta untuk bahasa pemrograman.

Kata-kata adalah entitas sintaksis untuk mewakili konsep semantik yang kurang lebih elementer. Tetapi konsep-konsep dasar ini harus disatukan dalam berbagai cara untuk memberikan makna yang lebih kompleks. Kami menulis the doguntuk menyampaikan bahwa yang kami maksud adalah anjing tertentu, dan the dog bites the catuntuk menyampaikan ide yang lebih kompleks. Tetapi cara mengatur kata-kata harus diperbaiki dengan aturan, sehingga kita dapat mengetahui anjing dan kucing mana yang benar-benar menggigit.

Jadi kami memiliki aturan seperti sentence -> subject verb complementyang seharusnya cocok dengan kalimat dan memberi tahu kami bagaimana ide yang terkait dengan masing-masing bagian diartikulasikan. Aturan-aturan ini adalah aturan sintaksis, karena aturan tersebut memberi tahu kita bagaimana representasi pesan kita diatur. The subjectsendiri bisa didefinisikan oleh aturan subject -> article noun, dan sebagainya.

2x+1=23x123

equation -> expression "=" expression  
expression -> expression "+" expression 
expression -> number

Struktur bahasa pemrogramannya sama. Bahasa pemrograman secara semantik khusus dalam mengekspresikan perhitungan yang harus dilakukan, daripada mengungkapkan masalah yang harus dipecahkan, bukti teorema atau hubungan persahabatan antara hewan. Tapi itulah perbedaan utama.

Representasi yang digunakan dalam sintaksis biasanya string karakter, atau suara untuk bahasa yang diucapkan. Semantik biasanya milik domain abstrak, atau mungkin realitas, tetapi masih diabstraksikan dalam proses pemikiran kita, atau pada domain perilaku perangkat. Komunikasi memerlukan pengodean informasi / ide ke dalam sintaksis, yang ditransmisikan dan diterjemahkan oleh penerima. Hasilnya kemudian diartikan dengan cara apa pun oleh penerima.

Jadi apa yang kita lihat dari bahasa ini sebagian besar sintaks dan strukturnya. Contoh di atas hanya salah satu cara paling umum untuk mendefinisikan string sintaksis dan organisasi strukturalnya. Ada yang lain. Untuk bahasa tertentu, beberapa string dapat diberi struktur, dan dikatakan milik bahasa, sementara yang lain tidak.

Hal yang sama berlaku untuk kata-kata. Beberapa urutan huruf (atau suara) adalah kata-kata yang sah, sementara yang lain tidak.

Bahasa formal hanya sintaksis tanpa semantik. Mereka mendefinisikan dengan seperangkat aturan urutan apa yang dapat dibangun, menggunakan elemen dasar alfabet. Apa aturannya bisa sangat bervariasi, terkadang rumit. Tetapi bahasa formal digunakan untuk banyak tujuan matematika di luar komunikasi linguistik, baik untuk bahasa pemrograman alami. Seperangkat aturan yang menentukan string dalam bahasa disebut tata bahasa. Tetapi ada banyak cara lain untuk mendefinisikan bahasa.

Dalam praktiknya, sebuah bahasa disusun dalam dua tingkat. Tingkat leksikal mendefinisikan kata-kata yang dibangun dari alfabet karakter. Tingkat sintaksis mendefinisikan kalimat, atau program yang dibangun dari alfabet kata (atau lebih tepatnya dari keluarga kata, sehingga tetap menjadi alfabet terbatas). Ini tentu agak disederhanakan.

Struktur kata-kata cukup sederhana di sebagian besar bahasa (pemrograman atau alami) sehingga biasanya didefinisikan dengan apa yang biasanya dianggap sebagai jenis bahasa formal yang paling sederhana: bahasa biasa. Mereka dapat didefinisikan dengan ekspresi reguler (regexp), dan cukup mudah diidentifikasi dengan perangkat yang diprogram yang disebut automata keadaan terbatas. Dalam kasus bahasa pemrograman, contoh kata adalah pengidentifikasi, integer, string, bilangan real, kata yang dicadangkan seperti if atau repeat, simbol tanda baca atau tanda kurung terbuka. Contoh keluarga kata adalah identifier, string, integer.

Tingkat sintaksis biasanya ditentukan oleh jenis bahasa formal yang sedikit lebih kompleks: bahasa bebas konteks, menggunakan kata-kata sebagai alfabet. Aturan yang telah kita lihat di atas adalah aturan bebas konteks untuk bahasa alami. Dalam hal aturan bahasa pemrograman dapat:

statement -> assignment
statement -> loop
loop ->  "while" expression "do" statement
assignment -> "identifier" "=" expression
expression -> "identifier"
expression -> "integer"
expression -> expression "operator" expression

Dengan aturan seperti itu, Anda dapat menulis:

while aaa /= bbb do aaa = aaa + bbb / 6 yang merupakan pernyataan.

Dan cara itu diproduksi dapat diwakili oleh struktur pohon yang disebut pohon parse atau pohon sintaks (tidak lengkap di sini):

                          statement
                              |
            _______________  loop _______________
           /      /                 \            \
      "while" expression           "do"       statement
       __________|_________                       |
      /          |         \                  assignment
 expression "operator" expression          _______|_______
     |           |          |             /       |       \
"identifier"   "/="   "identifier" "identifier"  "="   expression
     |                      |            |                 |
    aaa                    bbb          aaa             ... ...

Nama-nama yang muncul di sebelah kiri aturan disebut non-terminal, sedangkan kata-katanya disebut juga terminal, karena mereka berada dalam alfabet untuk bahasa (di atas tingkat leksikal). Non-terminal mewakili struktur sintaksis yang berbeda, yang dapat digunakan untuk menyusun program.

Aturan seperti itu disebut bebas konteks, karena non-terminal dapat diganti secara sewenang-wenang menggunakan salah satu aturan yang sesuai, terlepas dari konteks di mana ia muncul. Seperangkat aturan yang mendefinisikan bahasa disebut tata bahasa bebas konteks.

Sebenarnya ada batasan untuk itu, ketika pengidentifikasi harus dideklarasikan pertama kali, atau ketika ekspresi harus memenuhi batasan tipe. Tetapi pembatasan semacam itu dapat dianggap semantik, bukan sintaksis. Sebenarnya beberapa profesional menempatkan mereka dalam apa yang mereka sebut semantik statis .

Diberikan kalimat apa pun, program apa pun, makna kalimat itu diekstraksi dengan menganalisis struktur yang diberikan oleh pohon parse untuk kalimat ini. Oleh karena itu sangat penting untuk mengembangkan algoritma, yang disebut parser, yang dapat memulihkan struktur pohon yang sesuai dengan program, ketika diberikan program.

Pengurai didahului oleh penganalisa leksikal yang mengenali kata-kata, dan menentukan keluarga tempatnya. Kemudian urutan kata-kata, atau elemen leksikal, diberikan kepada parser yang mengambil struktur pohon yang mendasarinya. Dari struktur ini kompiler kemudian dapat menentukan bagaimana menghasilkan kode, yang merupakan bagian semantik dari pemrosesan program di sisi kompiler.

Parser dari kompiler dapat benar-benar membangun struktur data yang sesuai dengan parse-tree dan meneruskannya ke tahap selanjutnya dari proses kompilasi, tetapi tidak harus. Menjalankan jumlah algoritma parsing untuk mengembangkan strategi komputasi untuk mengeksplorasi pohon sintaksis yang tersirat dalam teks program. Sintaks / parse tree ini dapat atau tidak dapat dieksplorasi dalam proses, tergantung pada strategi kompilasi (jumlah tahapan). Apa yang diperlukan adalah bahwa pada akhirnya ada setidaknya satu eksplorasi bottom-up dari pohon parse, baik yang dieksplisit atau dibiarkan tersirat dalam struktur perhitungan.

Alasan untuk itu, secara intuitif, adalah bahwa cara formal standar untuk mendefinisikan semantik yang terkait dengan struktur pohon sintaksis adalah melalui apa yang disebut homomorfisme. Jangan takut kata besar. Idenya adalah hanya untuk mempertimbangkan makna keseluruhan dibangun dari makna bagian-bagian, atas dasar operator yang menghubungkan mereka

Misalnya, kalimatnya the dog bites the catbisa dianalisis dengan aturan sentence -> subject verb complement. Mengetahui makna dari ketiga sub pohon subject,, verbdan complement, aturan yang menyusunnya memberi tahu kita bahwa subjek sedang melakukan tindakan, dan bahwa kucinglah yang digigit.

Ini hanya penjelasan intuitif, tetapi bisa diformalkan. Semantik dibangun ke atas dari konstituen. Tapi ini menyembunyikan banyak kerumitan.

Kerja internal kompiler dapat didekomposisi menjadi beberapa tahap. Kompiler yang sebenarnya dapat bekerja tahap demi tahap, menggunakan representasi perantara. Mungkin juga menggabungkan beberapa tahapan. Ini tergantung pada teknologi yang digunakan dan pada kerumitan kompilasi bahasa yang ada.

babou
sumber
Luar biasa, sangat membantu. Saya mengerti bahwa regex digunakan dalam proses tokenization (misalnya string literal dapat didefinisikan dengan "[^"]*"dalam bentuknya yang paling sederhana, mengabaikan chars escape dll), tetapi apakah itu juga digunakan dalam membuat pohon sintaks (Berbicara dalam istilah bahasa pemrograman)? Saya kira tidak, sebagai automata keadaan terbatas, oleh definisi terbatas. Sebuah sintaksis pohon, bahkan untuk satu ifpernyataan, dapat secara teoritis tidak terbatas karena bersarang. Oleh karena itu regex, menjadi automata keadaan terbatas tidak dapat digunakan untuk tujuan menghasilkan pohon sintaks.
Zwander
@Zwander thx 4 editing - Contoh regex Anda sudah benar (saya seharusnya memberikan beberapa contoh). BTW, Regex juga merupakan bahasa, dengan semantiknya sendiri di dunia set string, dan dengan sintaks Context-Free ( CF ). Ini digunakan hanya untuk tokenisasi string bahasa, setidaknya untuk bahasa pemrograman, tidak biasanya dalam mendefinisikan sintaks yang lebih besar yang digunakan untuk pohon sintaks, kecuali sebagai tulisan pendek dalam Extended BNF (EBNF). Menambahkan Regex dalam beberapa bentuk ke formalisme yang lebih kompleks tidak mengubah kekuatan ekspresif mereka dalam banyak kasus. Komentar Anda tentang infinity tidak sepenuhnya benar. Lihat komentar selanjutnya.
babou
@Zwander Semua formalisme (bahasa formal) dijelaskan dengan baik. Itu adalah hipotesis mendasar. Bahkan jika Anda tertarik, katakanlah, tata bahasa CF dengan jumlah aturan yang tak terbatas, Anda harus memberikan deskripsi terbatas tentang aturan yang tak terhingga itu. Infinity juga memainkan trik pada Anda (tidak ada ruang untuk itu). Sebuah ifpernyataan tak terbatas (sewenang-wenang besar) tapi selalu terbatas. Infinite yang didefinisikan secara terbatas ifadalah a while. Perbedaan antara CF dan reguler adalah bahwa CF mengontrol / memungkinkan penyatuan (mis. Kuretisasi) sementara reguler tidak. Namun keduanya dijelaskan secara halus dan memungkinkan string tidak terbatas.
babou
1
@ Zwander Formalisme harus dapat mewakili kalimat (program) yang terbentuk dengan baik , tetapi hanya kalimat yang terbentuk dengan baik. Sederhananya, FSA tidak dapat menghitung tanpa batas. Jadi mereka tidak bisa tahu berapa banyak kurung yang dibuka yang harus ditutup, atau membuat sarang dengan benar dua jenis kurung yang berbeda. Banyak struktur linguistik memiliki tanda kurung "tersembunyi". Ini bukan hanya masalah pemeriksaan sintaksis, tetapi terutama menyiratkan bahwa struktur pohon yang sesuai tidak dapat diekspresikan dan dibangun, dari mana untuk menurunkan semantik. Memulihkan beberapa struktur pohon yang memadai membutuhkan penghitungan.
babou
1
(((SEBUAH-B)+3)×C)
2

Ada perbedaan yang signifikan. Yang paling utama di antara mereka, saya akan mengatakan, adalah parsing bahasa pemrograman nyata adalah semua tentang penanganan kesalahan sintaksis. Dengan bahasa formal Anda hanya akan mengatakan "baik itu tidak dalam bahasa", tetapi kompiler yang mengatakan itu tidak terlalu berguna - itu akan memberi tahu Anda apa yang salah, dan jika itu adalah kesalahan kecil, idealnya tetap parsing sehingga bisa laporkan lebih banyak kesalahan. Banyak penelitian (dan upaya implementasi) membahas hal itu. Jadi Anda benar-benar tidak terlalu peduli dengan hasil benar / salah, Anda hanya ingin menganalisis struktur input. Bahasa formal digunakan sebagai alat di sana, dan ada banyak tumpang tindih, tetapi Anda benar-benar memecahkan masalah yang berbeda.

Juga, dalam sebagian besar bahasa telah dipilih untuk tidak menegakkan hal-hal tertentu dalam tata bahasa , misalnya contoh yang Anda sebutkan, "variabel tidak dapat muncul jika belum dideklarasikan". Itu biasanya hal yang akan sepenuhnya diabaikan oleh parser, dan kemudian terperangkap dalam analisis terpisah (analisis semantik) yang melihat hal semacam itu dan tidak terpengaruh oleh pertimbangan seperti kelayakan konteks. Tetapi tidak selalu - misalnya untuk mem-parsing C, hack lexer sering digunakan, dan C ++ adalah contoh terkenal dari bahasa yang tidak dapat diuraikan tanpa secara bersamaan melakukan beberapa analisis semantik yang serius (sebenarnya mem-parsing C ++ tidak dapat diputuskan, karena templat Turing lengkap) ). Namun dalam bahasa yang lebih sederhana cenderung terpecah, lebih mudah seperti itu.

Harold
sumber
1

Bahasa formal adalah sekumpulan kata - kata adalah rangkaian simbol dari beberapa alfabet.

Ini berarti kopling Anda dari aturan produksi dan bahasa formal terlalu kuat. Itu tidak benar bahwa bahasa formal adalah aturan produksi. Sebaliknya aturan produksi menentukan bahasa formal. Bahasa formal adalah kata-kata yang dapat diproduksi oleh aturan produksi. (Ini mensyaratkan bahwa bahasa formal adalah jenis yang dapat didefinisikan oleh aturan produksi, misalnya bahasa reguler dapat didefinisikan oleh tata bahasa bebas konteks)

Jadi bahasa reguler yang sesuai dengan ekspresi (a|b)*c*ddidefinisikan oleh aturan produksi;

S->ACd
A->
A->aA
A->bA
C->
C->cC

Kata-kata yang dihasilkan oleh aturan produksi ini dari simbol awal S adalah string yang diterima oleh ekspresi reguler.

Taemyr
sumber
0

Ada hubungan lain antara ekspresi reguler dan bahasa pemrograman yang berkaitan dengan semantik. Konstruksi kontrol dasar bahasa imperatif adalah komposisi berurutan (lakukan A dan kemudian B), pilihan (lakukan A atau B), dan pengulangan (lakukan A lagi dan lagi).

Tiga cara yang sama untuk menggabungkan perilaku ditemukan dalam ekspresi reguler. Lemparkan panggilan subrutin dan Anda memiliki analogi dengan EBNF.

Jadi ada banyak kesamaan antara aljabar ekspresi reguler dan aljabar perintah. Ini dieksplorasi secara rinci oleh Dijkstra dalam "The Unification of Three Calculi". Ini juga merupakan dasar dari CCS Milner, yang memberikan jawaban atas pertanyaan: bagaimana jika kita menambahkan paralelisme?

Theodore Norvell
sumber