එය විශාල මාතෘකාවක් වන නමුත් විනෝදකාමී "පොතක් කියවන්න, ළමයෙක්" යනුවෙන් ඔබව තල්ලු කරනවා වෙනුවට ඒ වෙනුවට ඔබේ හිස එතීමට ඔබට උදව් කිරීමට මම ඔබට සතුටින් කරුණු දක්වන්නෙමි.
බොහෝ සම්පාදකයින් සහ / හෝ පරිවර්තකයන් මේ ආකාරයට ක්රියා කරයි:
ටෝකනයිස් කරන්න : කේත පෙළ පරිලෝකනය කර එය ටෝකන ලැයිස්තුවකට කඩා දමන්න.
ඔබට අවකාශය මත if (bar) foo += "a string";
නූල බෙදිය නොහැකි නිසා මෙම පියවර ව්යාකූල විය හැකිය, එය ටෝකන 8 ක ලැයිස්තුවක් බව ඔබ හඳුනාගත යුතුය : WORD, OPEN_PAREN, WORD, CLOSE_PAREN, WORD, ASIGNMENT_ADD, STRING_LITERAL, TERMINATOR. ඔබට පෙනෙන පරිදි, ප්රභව කේතය අවකාශයන්හි බෙදීම ක්රියා නොකරනු ඇත, ඔබට සෑම අක්ෂරයක්ම අනුක්රමයක් ලෙස කියවිය යුතුය, එබැවින් ඔබට අක්ෂර සංඛ්යාවක් හමු වුවහොත් ඔබ අක්ෂරාංක නොවන අක්ෂරයකට පහර දෙන තෙක් අක්ෂර කියවමින් සිටියි. කියවීම යනු පසුව තවදුරටත් වර්ගීකරණය කළ යුතු වචනයකි. ඔබේ ටෝකනයිසර් කෙතරම් කැටිති දැයි ඔබටම තීරණය කළ හැකිය: එය "a string"
STRING_LITERAL යනුවෙන් හැඳින්වෙන එක් ටෝකනයක් ලෙස ගිල දමන්නේද යන්න පසුව විග්රහ කිරීමටද, නැතහොත් එය දකින්නද?"a string"
OPEN_QUOTE, UNPARSED_TEXT, CLOSE_QUOTE හෝ වෙනත් ඕනෑම දෙයක් ලෙස, මෙය ඔබ කේත කරන විට ඔබ විසින්ම තීරණය කළ යුතු බොහෝ තේරීම්වලින් එකකි.
ලීක්ස් : ඉතින් දැන් ඔබට ටෝකන ලැයිස්තුවක් තිබේ. WORD වැනි නොපැහැදිලි වර්ගීකරණයක් සහිත ඔබ සමහර ටෝකන ටැග් කර ඇති නිසා පළමු පාස් එකේදී ඔබ එක් එක් අක්ෂර මාලාවේ සන්දර්භය හඳුනා ගැනීමට උත්සාහ කිරීම සඳහා වැඩි උත්සාහයක් නොගනී. එබැවින් දැන් ඔබේ මූලාශ්ර ටෝකන ලැයිස්තුව නැවත කියවා ඔබේ භාෂාවේ මූල පද මත පදනම්ව වඩාත් නිශ්චිත ටෝකන වර්ගයක් සහිත එක් එක් අපැහැදිලි ටෝකන නැවත වර්ගීකරණය කරන්න. එබැවින් ඔබට "if" වැනි "WORD" සහ "if" වැනි සංකේත IF නම් විශේෂ වචන ලැයිස්තුවක් ඇත, එබැවින් ඔබ එම ටෝකනයේ සංකේත වර්ගය WORD සිට IF දක්වා වෙනස් කරයි, සහ ඔබේ විශේෂ වචන ලැයිස්තුවේ නොමැති ඕනෑම වචනයක් , WORD foo වැනි, හඳුනාගැනීමක් වේ.
විග්රහ කරන්න : දැන් ඔබ if (bar) foo += "a string";
මේ ආකාරයට පෙනෙන ලීක්ස් ටෝකන ලැයිස්තුවක් හරවා ඇත: IF OPEN_PAREN IDENTIFER CLOSE_PAREN IDENTIFIER ASIGN_ADD STRING_LITERAL TERMINATOR. පියවර වන්නේ ටෝකනවල අනුපිළිවෙල ප්රකාශ ලෙස හඳුනා ගැනීමයි. මෙය විග්රහ කිරීමකි. ඔබ මෙය කරන්නේ ව්යාකරණ භාවිතා කිරීමෙනි:
ප්රකාශය: = ASIGN_EXPRESSION | IF_STATEMENT
IF_STATEMENT: = IF, PAREN_EXPRESSION, STATEMENT
ASIGN_EXPRESSION: = IDENTIFIER, ASIGN_OP, VALUE
PAREN_EXPRESSSION: = OPEN_PAREN, VALUE, CLOSE_PAREN
අගය: = හැඳුනුම්පත | STRING_LITERAL | PAREN_EXPRESSION
ASIGN_OP: = EQUAL | ASIGN_ADD | ASIGN_SUBTRACT | ASIGN_MULT
"|" භාවිතා කරන නිෂ්පාදන පද අතර අර්ථය “මේවායින් ඕනෑම එකක් ගැලපීම”, එය පද අතර කොමාව තිබේ නම් එහි තේරුම “මෙම පද අනුපිළිවෙලට ගැලපීම” යන්නයි.
ඔබ මෙය භාවිතා කරන්නේ කෙසේද? පළමු ටෝකනයෙන් පටන් ගෙන, ඔබේ නිෂ්පාදන සමඟ ඔබේ ටෝකන අනුක්රමය ගැලපීමට උත්සාහ කරන්න. එබැවින් පළමුව ඔබ ඔබේ ටෝකන් ලැයිස්තුව STATEMENT සමඟ ගැලපීමට උත්සාහ කරයි, එබැවින් ඔබ STATEMENT සඳහා වන රීතිය කියවන අතර එය "STATEMENT එකක් ASIGN_EXPRESSION හෝ IF_STATEMENT" යැයි පවසන බැවින් ඔබ මුලින් ASIGN_EXPRESSION හා සැසඳීමට උත්සාහ කරයි, එබැවින් ඔබ ASIGN_EXPRESSION සඳහා ව්යාකරණ රීතිය සොයා බලන්න. එය පවසන්නේ "ASIGN_EXPRESSION යනු ASIGN_OP හා පසුව VALUE ය, එබැවින් ඔබ IDENTIFIER සඳහා ව්යාකරණ රීතිය සොයා බලන අතර IDENTIFIER සඳහා ව්යාකරණ රීතියක් නොමැති බව ඔබට පෙනේ, එබැවින් IDENTIFIER" පර්යන්තයක් "යන්නෙන් තවදුරටත් අවශ්ය නොවේ එය ගැලපීම සඳහා විග්රහ කිරීම මඟින් ඔබට එය ඔබගේ ටෝකනය සමඟ කෙලින්ම ගැලපීමට උත්සාහ කළ හැකිය.නමුත් ඔබේ පළමු ප්රභව ටෝකනය IF වේ, සහ IF හැඳුනුම්පතක් හා සමාන නොවේ නම් තරගය අසාර්ථක විය. දැන් මොකද? ඔබ නැවත STATEMENT රීතිය වෙත ගොස් ඊළඟ වාරය ගැලපීමට උත්සාහ කරන්න: IF_STATEMENT. ඔබ සොයන්නේ IF_STATEMENT, එය ආරම්භ වන්නේ IF, බැලීමේ IF, IF ටර්මිනලයක් නම්, ඔබේ පළමු ටෝකනය සමඟ ටර්මිනලය සංසන්දනය කරන්න, IF ටෝකන් ගැලපීම්, නියමයි ඉදිරියට යන්න, ඊළඟ පදය PAREN_EXPRESSION, බලන්න PAREN_EXPRESSION, එය පර්යන්තයක් නොවේ, එය පළමු පදය කුමක්ද, PAREN_EXPRESSION ආරම්භ වන්නේ OPEN_PAREN, OPEN_PAREN බලන්න, එය පර්යන්තයක්, ඔබේ ඊළඟ ටෝකනයට OPEN_PAREN ගැලපෙන්න, එය ගැලපේ, සහ යනාදිය.
මෙම පියවරට ප්රවේශ වීමට ඇති පහසුම ක්රමය නම්, ඔබට ගැලපීමට උත්සාහ කරන ප්රභව කේත ටෝකනය සහ ඔබ එය ගැලපීමට උත්සාහ කරන ව්යාකරණ පදය පසුකර යන පාර්ස් () නම් ශ්රිතයක් ඇත. ව්යාකරණ පදය පර්යන්තයක් නොවේ නම් ඔබ නැවත යොමු කරයි: ඔබ නැවත විග්රහ කරන්නේ () නැවත එය එකම ප්රභව ටෝකනය පසු කර මෙම ව්යාකරණ රීතියේ පළමු පදයයි. මේ නිසා එය "පුනරාවර්තන සම්භවයක් ඇති පාර්සර්" ලෙස හැඳින්වේ. විග්රහ () ශ්රිතය ප්රභව ටෝකන කියවීමේදී ඔබගේ වර්තමාන තත්වය නැවත ලබා දෙයි (හෝ වෙනස් කරයි), එය අත්යවශ්යයෙන්ම ගැලපෙන අනුපිළිවෙලෙහි අවසාන ටෝකනය පසු කරයි, ඔබ ඊළඟ ඇමතුම දිගටම කරගෙන යයි () සිට විග්රහ කරන්න.
ASIGN_EXPRESSION වැනි නිශ්පාදනයකට ගැලපෙන සෑම අවස්ථාවකම () ඔබ එම කේත කොටස නියෝජනය කරන ව්යුහයක් නිර්මාණය කරයි. මෙම ව්යුහයේ මුල් ප්රභව ටෝකන සඳහා යොමු කිරීම් අඩංගු වේ. ඔබ මෙම ව්යුහයන්ගේ ලැයිස්තුවක් තැනීමට පටන් ගනී. අපි මෙම සම්පූර්ණ ව්යුහය වියුක්ත සින්ටැක්ස් ගස (AST) ලෙස හඳුන්වමු
සම්පාදනය කිරීම සහ / හෝ ක්රියාත්මක කිරීම : ඔබේ ව්යාකරණයේ ඇතැම් නිෂ්පාදන සඳහා ඔබ හසුරුවන කාර්යයන් නිර්මාණය කර ඇති අතර ඒඑස්ටී ව්යුහයක් ලබා දෙන්නේ නම් එය ඒඑස්ටී කැබැල්ල සම්පාදනය කිරීම හෝ ක්රියාත්මක කිරීම සිදු කරයි.
එබැවින් ASIGN_ADD වර්ගය ඇති ඔබේ AST හි කොටස දෙස බලමු. එබැවින් පරිවර්තකයෙකු ලෙස ඔබට ASIGN_ADD_execute () ශ්රිතයක් ඇත. මෙම ශ්රිතය විග්රහ කිරීමේ ගසට අනුරූප වන AST හි කොටසක් ලෙස සම්මත වේfoo += "a string"
, එබැවින් මෙම ශ්රිතය එම ව්යුහය දෙස බලන අතර ව්යුහයේ පළමු පදය IDENTIFIER විය යුතු බව දන්නා අතර දෙවන පදය VALUE වේ, එබැවින් ASIGN_ADD_execute () මතකයේ තක්සේරු කළ අගය නිරූපණය කරන වස්තුවක් නැවත ලබා දෙන VALUE_eval () ශ්රිතයක් වෙත VALUE පදය යවයි, ඉන්පසු ASIGN_ADD_execute () ඔබේ විචල්යතා වගුවේ “foo” සොයා බලයි, සහ eval_value () මගින් ආපසු ලබා දුන් ඕනෑම දෙයකට යොමු කිරීමක් ගබඩා කරයි. ශ්රිතය.
එය පරිවර්තකයෙකි. සම්පාදකයකුට ඒඑස්ටී ක්රියාත්මක කිරීම වෙනුවට ඒඑස්ටී බයිට් කේතයට හෝ යන්ත්ර කේතයට පරිවර්ථනය කරයි.
පියවර 1 සිට 3 දක්වා සහ 4 ක් පමණ ෆ්ලෙක්ස් සහ බයිසන් වැනි මෙවලම් භාවිතයෙන් පහසු කර ගත හැකිය. (aka. Lex සහ Yacc) නමුත් මුල සිටම පරිවර්ථකයෙකු ලිවීම ඕනෑම ක්රමලේඛකයෙකුට ලබා ගත හැකි වඩාත්ම බලගතු ව්යායාමය විය හැකිය. මෙය සමුළුවෙන් පසුව අනෙක් සියලුම ක්රමලේඛන අභියෝග ඉතා සුළු බව පෙනේ.
මගේ අවවාදය කුඩා වේ: ඉතා කුඩා භාෂාවක්, ඉතා කුඩා ව්යාකරණයක් ඇති අතර සරල ප්රකාශ කිහිපයක් විග්රහ කර ක්රියාත්මක කිරීමට උත්සාහ කරන්න, ඉන්පසු එතැන් සිට වර්ධනය වන්න.
මේවා කියවා, වාසනාව!
http://www.iro.umontreal.ca/~felipe/IFT2030-Automne2002/Complements/tinyc.c
http://en.wikipedia.org/wiki/Recursive_descent_parser
lex
,yacc
සහbison
.