{"id":5,"date":"2010-04-28T12:08:56","date_gmt":"2010-04-28T18:08:56","guid":{"rendered":"http:\/\/timothypoon.com\/blog\/?p=5"},"modified":"2010-05-04T15:28:43","modified_gmt":"2010-05-04T21:28:43","slug":"writing-a-compiler","status":"publish","type":"post","link":"https:\/\/timothypoon.com\/blog\/2010\/04\/28\/writing-a-compiler\/","title":{"rendered":"Writing A Compiler"},"content":{"rendered":"<p><a href=\"http:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2010\/04\/p9.jpg\"><img decoding=\"async\" src=\"http:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2010\/04\/p9.jpg\" alt=\"\" title=\"Compiler\" width=\"100%\" class=\"aligncenter size-full wp-image-44\" srcset=\"https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2010\/04\/p9.jpg 1280w, https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2010\/04\/p9-300x240.jpg 300w, https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2010\/04\/p9-1024x819.jpg 1024w\" sizes=\"(max-width: 1280px) 100vw, 1280px\" \/><\/a><\/p>\n<p>In my final semester of undergraduate collegiate studies (meaning I&#8217;ll hopefully be doing graduate shenanigans following this year), I decided to broaden my scope of computer science knowledge and drop myself into a graduate-level course on compilers. The professor for the course is <a title=\"Chair Dan Cooke\" href=\"http:\/\/www.cs.ttu.edu\/~dcooke\/\" target=\"_blank\">Daniel Cooke<\/a>, a pretty big name in the world of computer languages, NASA intelligence systems, and AI and logic. His most prolific brainchild is probably <a title=\"SequenceL - An Overview of a Simple Language\" href=\"http:\/\/www.cs.ttu.edu\/~dcooke\/PLC3018.pdf\" target=\"_blank\">SequenceL<\/a>, a high performance <a title=\"Declarative programming - Wikipedia, the free encyclopedia\" href=\"http:\/\/en.wikipedia.org\/wiki\/Declarative_programming\">declarative language<\/a> that rips traditional languages a new one in terms of speed.<\/p>\n<p>Anyways, for the entire course, we the students were to build a complete <a title=\"LL parser - Wikipedia, the free encyclopedia\" href=\"http:\/\/en.wikipedia.org\/wiki\/LL_parser\" target=\"_blank\">LL(1) parser<\/a>-based compiler from lexical analysis to syntax to semantics to optimization and finally to code generation for an admittedly simplistic <a title=\"Context-free grammar - Wikipedia, the free encyclopedia\" href=\"http:\/\/en.wikipedia.org\/wiki\/Context-free_grammar\" target=\"_blank\">context-free grammar<\/a>. The LL(1) essentially breaks down into three parts for explanation:<\/p>\n<ul>\n<li>The first L means that the grammar is parsed from left to right,<\/li>\n<li>The second L means that the grammar is parsed based on the left-most derivation (as opposed to an <a title=\"LR parser - Wikipedia, the free encyclopedia\" href=\"http:\/\/en.wikipedia.org\/wiki\/LR_parser\">LR parser<\/a>),<\/li>\n<li>The (1) means that the parser can look ahead at most one token<\/li>\n<\/ul>\n<p>I won&#8217;t bother to go indepth about the intricacies of what a context-free grammar is as that is probably better suited for a full-blown <a title=\"Automata theory - Wikipedia, the free encyclopedia\" href=\"http:\/\/en.wikipedia.org\/wiki\/Automata_theory\" target=\"_blank\">automata theory<\/a> course.<\/p>\n<h2>The Grammar<\/h2>\n<p>Back to business, though, our grammar goes a little something like this. I won&#8217;t bore you with the entire thing, but here&#8217;s the gist of it:<\/p>\n<ul>\n<li>S ::= ID := E S1 | read(IDL S1 | write(IDL S1 | case C do S M S1 | while C do S od S1 | if C then S S2 | foreach id in id do S od S1<\/li>\n<li>S1 ::= ; S | \u03b5<\/li>\n<li>S2 ::= fi S1 | else S fi S1<\/li>\n<li>M ::= : C do S M | esac<\/li>\n<\/ul>\n<p>E&#8217;s are expressions of positive integers and identifiers (variables which may or may not be arrays of any dimension) with operations for +, -, *, and \u00f7 as well as being raised to some power with exp(E, E). C&#8217;s are conditional statements of E statements joined by &lt;, &gt;, or = and &#8220;AND&#8221; or &#8220;OR&#8221; operations in between as well as a negating NOT(C) operation. There&#8217;s also some variable declaration stuff before all that wrapped up in some &#8220;program,&#8221; &#8220;begin,&#8221; and &#8220;end&#8221; tokens. Pretty simple, right?<\/p>\n<h2>The Code<\/h2>\n<p>Our first step is to write up a tokenizer (in C++) that spits out tokens as necessary. This comprises of the entire lexical analysis portion of the compiler since its only job is to look for words of the program (hence &#8220;lexical&#8221;) and return errors if there are any. In this case, we have a limited word length, a list of known and unknown characters, and the rule that identifiers can&#8217;t start with numbers.<\/p>\n<div class=\"codecolorer-container cpp railscasts\" style=\"overflow:auto;white-space:nowrap;width:100%;height:300px;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/>16<br \/>17<br \/>18<br \/>19<br \/>20<br \/>21<br \/>22<br \/>23<br \/>24<br \/>25<br \/>26<br \/>27<br \/>28<br \/>29<br \/>30<br \/>31<br \/>32<br \/>33<br \/>34<br \/>35<br \/>36<br \/>37<br \/>38<br \/>39<br \/>40<br \/>41<br \/>42<br \/><\/div><\/td><td><div class=\"cpp codecolorer\"><span class=\"kw4\">bool<\/span> token<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Tokenizer<\/span><br \/>\n&nbsp; &nbsp; resetctkn<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Reset the current token<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">while<\/span><span class=\"br0\">&#40;<\/span><span class=\"nu0\">1<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>linepos <span class=\"sy1\">&gt;=<\/span> linesize<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Finished with the current line<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>checktkn<span class=\"br0\">&#40;<\/span>ctkn<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"kw1\">return<\/span> <span class=\"kw2\">true<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; resetctkn<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span><span class=\"sy3\">!<\/span>newline<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"kw1\">return<\/span> <span class=\"kw2\">false<\/span><span class=\"sy4\">;<\/span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Out of lines<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">continue<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>cmnt <span class=\"sy1\">==<\/span> 1line.<span class=\"me1\">at<\/span> <span class=\"sy3\">&amp;&amp;<\/span> <span class=\"br0\">&#40;<\/span>linepos<span class=\"br0\">&#41;<\/span> <span class=\"sy1\">==<\/span> <span class=\"st0\">'*'<\/span> <span class=\"sy3\">&amp;&amp;<\/span> line.<span class=\"me1\">at<\/span><span class=\"br0\">&#40;<\/span>linepos<span class=\"sy2\">+<\/span><span class=\"nu0\">1<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy1\">==<\/span> <span class=\"st0\">'\/'<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cmnt <span class=\"sy1\">=<\/span> <span class=\"nu0\">0<\/span><span class=\"sy4\">;<\/span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Set comment flag<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; linepos <span class=\"sy2\">+<\/span><span class=\"sy1\">=<\/span> <span class=\"nu0\">2<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">continue<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>cmnt <span class=\"sy1\">==<\/span> <span class=\"nu0\">0<\/span> <span class=\"sy3\">&amp;&amp;<\/span> line.<span class=\"me1\">at<\/span><span class=\"br0\">&#40;<\/span>linepos<span class=\"br0\">&#41;<\/span> <span class=\"sy1\">==<\/span> <span class=\"st0\">'\/'<\/span> <span class=\"sy3\">&amp;&amp;<\/span> line.<span class=\"me1\">at<\/span><span class=\"br0\">&#40;<\/span>linepos<span class=\"sy2\">+<\/span><span class=\"nu0\">1<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy1\">==<\/span> <span class=\"st0\">'*'<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cmnt <span class=\"sy1\">=<\/span> <span class=\"nu0\">1<\/span><span class=\"sy4\">;<\/span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Reset comment flag<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; linepos <span class=\"sy2\">+<\/span><span class=\"sy1\">=<\/span> <span class=\"nu0\">2<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">continue<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>cmnt <span class=\"sy1\">==<\/span> <span class=\"nu0\">1<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Skip until comment ends<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; linepos<span class=\"sy2\">++<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">continue<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>tsize <span class=\"sy1\">&gt;=<\/span> TOKENSIZE<span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Lexical error in token size<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw3\">log<\/span><span class=\"br0\">&#40;<\/span><span class=\"st0\">'Lexical Error: token size exceeds maximum length'<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>checktkn<span class=\"br0\">&#40;<\/span>ctkn<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"kw1\">return<\/span> <span class=\"kw2\">true<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; resetctkn<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Skip spaces<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">while<\/span><span class=\"br0\">&#40;<\/span>line.<span class=\"me1\">at<\/span><span class=\"br0\">&#40;<\/span>linepos<span class=\"br0\">&#41;<\/span> <span class=\"sy1\">==<\/span> <span class=\"st0\">' '<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy3\">&amp;&amp;<\/span> linepos <span class=\"sy1\">&lt;<\/span> <span class=\"br0\">&#40;<\/span>linesize <span class=\"sy2\">-<\/span> <span class=\"nu0\">1<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span> linepos<span class=\"sy2\">++<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; ctkn<span class=\"br0\">&#91;<\/span>tsize<span class=\"br0\">&#93;<\/span> <span class=\"sy1\">=<\/span> <span class=\"kw3\">tolower<\/span><span class=\"br0\">&#40;<\/span>line.<span class=\"me1\">at<\/span><span class=\"br0\">&#40;<\/span>linepos<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"co1\">\/\/ Check token if a delimiter is found<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>delimiter<span class=\"br0\">&#40;<\/span>line.<span class=\"me1\">at<\/span><span class=\"br0\">&#40;<\/span>linepos<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"sy3\">||<\/span> delimiter<span class=\"br0\">&#40;<\/span>line.<span class=\"me1\">at<\/span><span class=\"br0\">&#40;<\/span>linepos<span class=\"sy2\">+<\/span><span class=\"nu0\">1<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; linepos<span class=\"sy2\">++<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">if<\/span><span class=\"br0\">&#40;<\/span>checktkn<span class=\"br0\">&#40;<\/span>ctkn<span class=\"br0\">&#41;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"kw1\">return<\/span> <span class=\"kw2\">true<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; resetctkn<span class=\"br0\">&#40;<\/span><span class=\"br0\">&#41;<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw1\">continue<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; tsize<span class=\"sy2\">++<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; linepos<span class=\"sy2\">++<\/span><span class=\"sy4\">;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"br0\">&#125;<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>I&#8217;ve kept things pretty simple in that I won&#8217;t explicitly go over the helper functions&#8217; code, though I will go over what they do.<\/p>\n<ul>\n<li>Delimiter() returns true if a character is a delimiter.<\/li>\n<li>Checktkn() checks if a string is a valid token and sets the appropriate variable values in the symbol table for syntax and semantics analysis.<\/li>\n<li>Resetctkn() simply resets the variables used for tracking the tokenizer&#8217;s progress through a line.<\/li>\n<li>Log() just logs errors into the console and the listing file.<\/li>\n<\/ul>\n<p>This could almost definitely be optimized, but you get the idea. Next time, syntax!<\/p>\n","protected":false},"excerpt":{"rendered":"<p><a href=\"http:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2010\/04\/p9.jpg\"><img decoding=\"async\" src=\"http:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2010\/04\/p9.jpg\" alt=\"\" title=\"Compiler\" width=\"100%\" class=\"aligncenter size-full wp-image-44\" srcset=\"https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2010\/04\/p9.jpg 1280w, https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2010\/04\/p9-300x240.jpg 300w, https:\/\/timothypoon.com\/blog\/wp-content\/uploads\/2010\/04\/p9-1024x819.jpg 1024w\" sizes=\"(max-width: 1280px) 100vw, 1280px\" \/><\/a><\/p>\n<p>In my final semester of undergraduate collegiate studies (meaning I&#8217;ll hopefully be doing graduate shenanigans following this year), I decided to broaden my scope of computer science knowledge and drop myself into a graduate-level course on compilers. The professor for the course is <a title=\"Chair Dan Cooke\" href=\"http:\/\/www.cs.ttu.edu\/~dcooke\/\" target=\"_blank\">Daniel Cooke<\/a>, a pretty big name in the world of computer languages, NASA intelligence systems, and AI and logic. His most prolific brainchild is probably <a title=\"SequenceL - An Overview of a Simple Language\" href=\"http:\/\/www.cs.ttu.edu\/~dcooke\/PLC3018.pdf\" target=\"_blank\">SequenceL<\/a>, a high performance <a title=\"Declarative programming - Wikipedia, the free encyclopedia\" href=\"http:\/\/en.wikipedia.org\/wiki\/Declarative_programming\">declarative language<\/a> that rips traditional languages a new one in terms of speed.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[7],"class_list":["post-5","post","type-post","status-publish","format-standard","hentry","category-code","tag-compiler","et-no-image","et-bg-layout-dark","et-white-bg"],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p462yg-5","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/posts\/5","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/comments?post=5"}],"version-history":[{"count":0,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/posts\/5\/revisions"}],"wp:attachment":[{"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/media?parent=5"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/categories?post=5"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/timothypoon.com\/blog\/wp-json\/wp\/v2\/tags?post=5"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}