website

Website contents
git clone git://git.reagancfischer.dev/website.git
Log | Files | Refs

commit 15d0687bdf6a0f9662be28539ca5b7c9d8952ad6
parent 361ae256638c968e45658d52e4049ea12b05ca92
Author: Reagan <rfische2@uccs.edu>
Date:   Mon, 26 Aug 2024 20:25:41 -0600

AST

Diffstat:
Mcontact.html | 4++--
Mprojects.html | 5-----
Aprojects/cminus/ast.html | 2325+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aprojects/cminus/code/ast.c | 1422+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aprojects/cminus/code/ast.h | 320+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aprojects/cminus/code/ast.lit | 1898+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mprojects/cminus/code/lexer.lit | 59++++++++++++++++++++++++++++++++++++++++++++++-------------
Mprojects/cminus/code/makefile | 6++++++
Aprojects/cminus/code/parser.lit | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Mprojects/cminus/code/token.c | 50++++++++++----------------------------------------
Mprojects/cminus/code/token.h | 1+
Mprojects/cminus/code/tokenizer.c | 10+++++++++-
Aprojects/cminus/code/util.c | 44++++++++++++++++++++++++++++++++++++++++++++
Aprojects/cminus/code/util.h | 9+++++++++
Mprojects/cminus/lexer.html | 342+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Aprojects/cminus/parser.html | 251+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16 files changed, 6587 insertions(+), 208 deletions(-)

diff --git a/contact.html b/contact.html @@ -27,8 +27,8 @@ </header> <main> - <p>You can contact me <a href="mailto:reagan@thespringstechguy.com?subject=Question">by e-mail - (reagan@thespringstechguy.com)</a>.</p> + <p>You can contact me <a href="mailto:reagan@reagancfischer.dev">by e-mail + (reagan@reagancfischer.dev)</a>.</p> </main> diff --git a/projects.html b/projects.html @@ -72,11 +72,6 @@ self-hosting. It'll support all C99 features except for: </p> <ul> - <li> - Typedefs without the _t suffix and conversely variable declarations - with the _t suffix (so I don't have to implement the Lexer hack/symbol - table feedback loop) - </li> <li>Inline Assembly</li> <li>Variable Length Arrays</li> <li>Complex/Imaginary numbers</li> diff --git a/projects/cminus/ast.html b/projects/cminus/ast.html @@ -0,0 +1,2325 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>AST code</title> +<script> +!function(){var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; +(function(){function R(a){function d(e){var b=e.charCodeAt(0);if(b!==92)return b;var a=e.charAt(1);return(b=r[a])?b:"0"<=a&&a<="7"?parseInt(e.substring(1),8):a==="u"||a==="x"?parseInt(e.substring(2),16):e.charCodeAt(1)}function g(e){if(e<32)return(e<16?"\\x0":"\\x")+e.toString(16);e=String.fromCharCode(e);return e==="\\"||e==="-"||e==="]"||e==="^"?"\\"+e:e}function b(e){var b=e.substring(1,e.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),e=[],a= +b[0]==="^",c=["["];a&&c.push("^");for(var a=a?1:0,f=b.length;a<f;++a){var h=b[a];if(/\\[bdsw]/i.test(h))c.push(h);else{var h=d(h),l;a+2<f&&"-"===b[a+1]?(l=d(b[a+2]),a+=2):l=h;e.push([h,l]);l<65||h>122||(l<65||h>90||e.push([Math.max(65,h)|32,Math.min(l,90)|32]),l<97||h>122||e.push([Math.max(97,h)&-33,Math.min(l,122)&-33]))}}e.sort(function(e,a){return e[0]-a[0]||a[1]-e[1]});b=[];f=[];for(a=0;a<e.length;++a)h=e[a],h[0]<=f[1]+1?f[1]=Math.max(f[1],h[1]):b.push(f=h);for(a=0;a<b.length;++a)h=b[a],c.push(g(h[0])), +h[1]>h[0]&&(h[1]+1>h[0]&&c.push("-"),c.push(g(h[1])));c.push("]");return c.join("")}function s(e){for(var a=e.source.match(/\[(?:[^\\\] ]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),c=a.length,d=[],f=0,h=0;f<c;++f){var l=a[f];l==="("?++h:"\\"===l.charAt(0)&&(l=+l.substring(1))&&(l<=h?d[l]=-1:a[f]=g(l))}for(f=1;f<d.length;++f)-1===d[f]&&(d[f]=++x);for(h=f=0;f<c;++f)l=a[f],l==="("?(++h,d[h]||(a[f]="(?:")):"\\"===l.charAt(0)&&(l=+l.substring(1))&&l<=h&& +(a[f]="\\"+d[l]);for(f=0;f<c;++f)"^"===a[f]&&"^"!==a[f+1]&&(a[f]="");if(e.ignoreCase&&m)for(f=0;f<c;++f)l=a[f],e=l.charAt(0),l.length>=2&&e==="["?a[f]=b(l):e!=="\\"&&(a[f]=l.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return a.join("")}for(var x=0,m=!1,j=!1,k=0,c=a.length;k<c;++k){var i=a[k];if(i.ignoreCase)j=!0;else if(/[a-z]/i.test(i.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){m=!0;j=!1;break}}for(var r={b:8,t:9,n:10,v:11, +f:12,r:13},n=[],k=0,c=a.length;k<c;++k){i=a[k];if(i.global||i.multiline)throw Error(""+i);n.push("(?:"+s(i)+")")}return RegExp(n.join("|"),j?"gi":"g")}function S(a,d){function g(a){var c=a.nodeType;if(c==1){if(!b.test(a.className)){for(c=a.firstChild;c;c=c.nextSibling)g(c);c=a.nodeName.toLowerCase();if("br"===c||"li"===c)s[j]="\n",m[j<<1]=x++,m[j++<<1|1]=a}}else if(c==3||c==4)c=a.nodeValue,c.length&&(c=d?c.replace(/\r\n?/g,"\n"):c.replace(/[\t\n\r ]+/g," "),s[j]=c,m[j<<1]=x,x+=c.length,m[j++<<1|1]= +a)}var b=/(?:^|\s)nocode(?:\s|$)/,s=[],x=0,m=[],j=0;g(a);return{a:s.join("").replace(/\n$/,""),d:m}}function H(a,d,g,b){d&&(a={a:d,e:a},g(a),b.push.apply(b,a.g))}function T(a){for(var d=void 0,g=a.firstChild;g;g=g.nextSibling)var b=g.nodeType,d=b===1?d?a:g:b===3?U.test(g.nodeValue)?a:d:d;return d===a?void 0:d}function D(a,d){function g(a){for(var j=a.e,k=[j,"pln"],c=0,i=a.a.match(s)||[],r={},n=0,e=i.length;n<e;++n){var z=i[n],w=r[z],t=void 0,f;if(typeof w==="string")f=!1;else{var h=b[z.charAt(0)]; +if(h)t=z.match(h[1]),w=h[0];else{for(f=0;f<x;++f)if(h=d[f],t=z.match(h[1])){w=h[0];break}t||(w="pln")}if((f=w.length>=5&&"lang-"===w.substring(0,5))&&!(t&&typeof t[1]==="string"))f=!1,w="src";f||(r[z]=w)}h=c;c+=z.length;if(f){f=t[1];var l=z.indexOf(f),B=l+f.length;t[2]&&(B=z.length-t[2].length,l=B-f.length);w=w.substring(5);H(j+h,z.substring(0,l),g,k);H(j+h+l,f,I(w,f),k);H(j+h+B,z.substring(B),g,k)}else k.push(j+h,w)}a.g=k}var b={},s;(function(){for(var g=a.concat(d),j=[],k={},c=0,i=g.length;c<i;++c){var r= +g[c],n=r[3];if(n)for(var e=n.length;--e>=0;)b[n.charAt(e)]=r;r=r[1];n=""+r;k.hasOwnProperty(n)||(j.push(r),k[n]=q)}j.push(/[\S\s]/);s=R(j)})();var x=d.length;return g}function v(a){var d=[],g=[];a.tripleQuotedStrings?d.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?d.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, +q,"'\"`"]):d.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&g.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var b=a.hashComments;b&&(a.cStyleComments?(b>1?d.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):d.push(["com",/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),g.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,q])):d.push(["com", +/^#[^\n\r]*/,q,"#"]));a.cStyleComments&&(g.push(["com",/^\/\/[^\n\r]*/,q]),g.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));if(b=a.regexLiterals){var s=(b=b>1?"":"\n\r")?".":"[\\S\\s]";g.push(["lang-regex",RegExp("^(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*("+("/(?=[^/*"+b+"])(?:[^/\\x5B\\x5C"+b+"]|\\x5C"+s+"|\\x5B(?:[^\\x5C\\x5D"+b+"]|\\x5C"+ +s+")*(?:\\x5D|$))+/")+")")])}(b=a.types)&&g.push(["typ",b]);b=(""+a.keywords).replace(/^ | $/g,"");b.length&&g.push(["kwd",RegExp("^(?:"+b.replace(/[\s,]+/g,"|")+")\\b"),q]);d.push(["pln",/^\s+/,q," \r\n\t\u00a0"]);b="^.[^\\s\\w.$@'\"`/\\\\]*";a.regexLiterals&&(b+="(?!s*/)");g.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/, +q],["pun",RegExp(b),q]);return D(d,g)}function J(a,d,g){function b(a){var c=a.nodeType;if(c==1&&!x.test(a.className))if("br"===a.nodeName)s(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)b(a);else if((c==3||c==4)&&g){var d=a.nodeValue,i=d.match(m);if(i)c=d.substring(0,i.index),a.nodeValue=c,(d=d.substring(i.index+i[0].length))&&a.parentNode.insertBefore(j.createTextNode(d),a.nextSibling),s(a),c||a.parentNode.removeChild(a)}}function s(a){function b(a,c){var d= +c?a.cloneNode(!1):a,e=a.parentNode;if(e){var e=b(e,1),g=a.nextSibling;e.appendChild(d);for(var i=g;i;i=g)g=i.nextSibling,e.appendChild(i)}return d}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),d;(d=a.parentNode)&&d.nodeType===1;)a=d;c.push(a)}for(var x=/(?:^|\s)nocode(?:\s|$)/,m=/\r\n?|\n/,j=a.ownerDocument,k=j.createElement("li");a.firstChild;)k.appendChild(a.firstChild);for(var c=[k],i=0;i<c.length;++i)b(c[i]);d===(d|0)&&c[0].setAttribute("value",d);var r=j.createElement("ol"); +r.className="linenums";for(var d=Math.max(0,d-1|0)||0,i=0,n=c.length;i<n;++i)k=c[i],k.className="L"+(i+d)%10,k.firstChild||k.appendChild(j.createTextNode("\u00a0")),r.appendChild(k);a.appendChild(r)}function p(a,d){for(var g=d.length;--g>=0;){var b=d[g];F.hasOwnProperty(b)?E.console&&console.warn("cannot override language handler %s",b):F[b]=a}}function I(a,d){if(!a||!F.hasOwnProperty(a))a=/^\s*</.test(d)?"default-markup":"default-code";return F[a]}function K(a){var d=a.h;try{var g=S(a.c,a.i),b=g.a; +a.a=b;a.d=g.d;a.e=0;I(d,b)(a);var s=/\bMSIE\s(\d+)/.exec(navigator.userAgent),s=s&&+s[1]<=8,d=/\n/g,x=a.a,m=x.length,g=0,j=a.d,k=j.length,b=0,c=a.g,i=c.length,r=0;c[i]=m;var n,e;for(e=n=0;e<i;)c[e]!==c[e+2]?(c[n++]=c[e++],c[n++]=c[e++]):e+=2;i=n;for(e=n=0;e<i;){for(var p=c[e],w=c[e+1],t=e+2;t+2<=i&&c[t+1]===w;)t+=2;c[n++]=p;c[n++]=w;e=t}c.length=n;var f=a.c,h;if(f)h=f.style.display,f.style.display="none";try{for(;b<k;){var l=j[b+2]||m,B=c[r+2]||m,t=Math.min(l,B),A=j[b+1],G;if(A.nodeType!==1&&(G=x.substring(g, +t))){s&&(G=G.replace(d,"\r"));A.nodeValue=G;var L=A.ownerDocument,o=L.createElement("span");o.className=c[r+1];var v=A.parentNode;v.replaceChild(o,A);o.appendChild(A);g<l&&(j[b+1]=A=L.createTextNode(x.substring(t,l)),v.insertBefore(A,o.nextSibling))}g=t;g>=l&&(b+=2);g>=B&&(r+=2)}}finally{if(f)f.style.display=h}}catch(u){E.console&&console.log(u&&u.stack||u)}}var E=window,y=["break,continue,do,else,for,if,return,while"],C=[[y,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],M=[C,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],V=[C,"abstract,assert,boolean,byte,extends,final,finally,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"], +N=[C,"abstract,as,base,bool,by,byte,checked,decimal,delegate,descending,dynamic,event,finally,fixed,foreach,from,group,implicit,in,interface,internal,into,is,let,lock,null,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"],C=[C,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],O=[y,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], +P=[y,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],W=[y,"as,assert,const,copy,drop,enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,pub,pure,ref,self,static,struct,true,trait,type,unsafe,use"],y=[y,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],Q=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/, +U=/\S/,X=v({keywords:[M,N,C,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",O,P,y],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),F={};p(X,["default-code"]);p(D([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-", +/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i] ]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);p(D([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"] ],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/], +["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",/^style\s*=\s*([^\s"'>]+)/i] ]),["in.tag"]);p(D([],[["atv",/^[\S\s]+/] ]),["uq.val"]);p(v({keywords:M,hashComments:!0,cStyleComments:!0,types:Q}),["c","cc","cpp","cxx","cyc","m"]);p(v({keywords:"null,true,false"}),["json"]);p(v({keywords:N,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:Q}), +["cs"]);p(v({keywords:V,cStyleComments:!0}),["java"]);p(v({keywords:y,hashComments:!0,multiLineStrings:!0}),["bash","bsh","csh","sh"]);p(v({keywords:O,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),["cv","py","python"]);p(v({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:2}),["perl","pl","pm"]);p(v({keywords:P, +hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb","ruby"]);p(v({keywords:C,cStyleComments:!0,regexLiterals:!0}),["javascript","js"]);p(v({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes",hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);p(v({keywords:W,cStyleComments:!0,multilineStrings:!0}),["rc","rs","rust"]); +p(D([],[["str",/^[\S\s]+/] ]),["regex"]);var Y=E.PR={createSimpleLexer:D,registerLangHandler:p,sourceDecorator:v,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ",prettyPrintOne:E.prettyPrintOne=function(a,d,g){var b=document.createElement("div");b.innerHTML="<pre>"+a+"</pre>";b=b.firstChild;g&&J(b,g,!0);K({h:d,j:g,c:b,i:1}); +return b.innerHTML},prettyPrint:E.prettyPrint=function(a,d){function g(){for(var b=E.PR_SHOULD_USE_CONTINUATION?c.now()+250:Infinity;i<p.length&&c.now()<b;i++){for(var d=p[i],j=h,k=d;k=k.previousSibling;){var m=k.nodeType,o=(m===7||m===8)&&k.nodeValue;if(o?!/^\??prettify\b/.test(o):m!==3||/\S/.test(k.nodeValue))break;if(o){j={};o.replace(/\b(\w+)=([\w%+\-.:]+)/g,function(a,b,c){j[b]=c});break}}k=d.className;if((j!==h||e.test(k))&&!v.test(k)){m=!1;for(o=d.parentNode;o;o=o.parentNode)if(f.test(o.tagName)&& +o.className&&e.test(o.className)){m=!0;break}if(!m){d.className+=" prettyprinted";m=j.lang;if(!m){var m=k.match(n),y;if(!m&&(y=T(d))&&t.test(y.tagName))m=y.className.match(n);m&&(m=m[1])}if(w.test(d.tagName))o=1;else var o=d.currentStyle,u=s.defaultView,o=(o=o?o.whiteSpace:u&&u.getComputedStyle?u.getComputedStyle(d,q).getPropertyValue("white-space"):0)&&"pre"===o.substring(0,3);u=j.linenums;if(!(u=u==="true"||+u))u=(u=k.match(/\blinenums\b(?::(\d+))?/))?u[1]&&u[1].length?+u[1]:!0:!1;u&&J(d,u,o);r= +{h:m,c:d,j:u,i:o};K(r)}}}i<p.length?setTimeout(g,250):"function"===typeof a&&a()}for(var b=d||document.body,s=b.ownerDocument||document,b=[b.getElementsByTagName("pre"),b.getElementsByTagName("code"),b.getElementsByTagName("xmp")],p=[],m=0;m<b.length;++m)for(var j=0,k=b[m].length;j<k;++j)p.push(b[m][j]);var b=q,c=Date;c.now||(c={now:function(){return+new Date}});var i=0,r,n=/\blang(?:uage)?-([\w.]+)(?!\S)/,e=/\bprettyprint\b/,v=/\bprettyprinted\b/,w=/pre|xmp/i,t=/^code$/i,f=/^(?:pre|code|xmp)$/i, +h={};g()}};typeof define==="function"&&define.amd&&define("google-code-prettify",[],function(){return Y})})();}() +</script> +<style> +.pln{color:#1b181b}.str{color:#918b3b}.kwd{color:#7b59c0}.com{color:#9e8f9e}.typ{color:#516aec}.lit{color:#a65926}.clo,.opn,.pun{color:#1b181b}.tag{color:#ca402b}.atn{color:#a65926}.atv{color:#159393}.dec{color:#a65926}.var{color:#ca402b}.fun{color:#516aec}pre.prettyprint{background:#f7f3f7;color:#ab9bab;font-family:Menlo,Consolas,"Bitstream Vera Sans Mono","DejaVu Sans Mono",Monaco,monospace;font-size:12px;line-height:1.5;border:1px solid #d8cad8;padding:10px}ol.linenums{margin-top:0;margin-bottom:0} +body{min-width:200px;max-width:850px;margin:0 auto;padding:30px;}.chapter-nav{font-size: 10pt;}a:link,a:visited{color:#00f}.codeblock_name,code,pre.prettyprint{font-family:Monaco,"Lucida Console",monospace}body{font-size:14pt}.codeblock_name,.math,.seealso,code{font-size:10pt}.codeblock{page-break-inside:avoid;padding-bottom:15px}.math{text-indent:0}pre.prettyprint{font-size:10pt;padding:10px;border-radius:10px;border:none;white-space:pre-wrap}.codeblock_name{margin-top:1.25em;display:block}a:link{text-decoration:none}a:link:not(.lit):hover{color:#00f;text-decoration:underline}a:link:active{color:red}h4{padding-right:1.25em}h4.noheading{margin-bottom:0}h1{text-align:center}code{padding:2px}pre{-moz-tab-size:4;-o-tab-size:4;tab-size:4}p:not(.notp){margin:0;text-indent:2em}.two-col{list-style-type:none}.two-col li:before{content:'-';padding:5px;margin-right:5px;color:orange;background-color:#fff;display:inline-block}@media print{body{font-size:10pt}pre.prettyprint{font-size:8pt}.seealso{font-size:9pt}.codeblock_name,.math,code{font-size:8pt}.math{text-indent:0}} +/* code blocks (Style from jmeiners.com/lc3-vm, CC BY-NC-SA 4.0, used with attribution) */ + +/* Quotes and Block Quotes */ +blockquote { + margin: 1.5em 10px; + padding: 0.5em 10px; + border-left: 5px solid #ccc; + color: #666; + background-color: #f9f9f9; + font-style: italic; +} + +blockquote p { + margin: 0; + font-size: 1.2em; +} + +q { + quotes: "“" "”" "‘" "’"; + font-style: italic; +} + +q::before { + content: open-quote; +} + +q::after { + content: close-quote; +} + +/*! Color themes for Google Code Prettify | MIT License | github.com/jmblog/color-themes-for-google-code-prettify */ +.prettyprint { + background: #f5f7ff; + font-family: Menlo, "Bitstream Vera Sans Mono", "DejaVu Sans Mono", Monaco, Consolas, monospace; + border: 0 !important; +} + +.pln { + color: #202746; +} + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; + color: #202746; +} + +li.L0, +li.L1, +li.L2, +li.L3, +li.L4, +li.L5, +li.L6, +li.L7, +li.L8, +li.L9 { + padding-left: 1em; + background-color: #f5f7ff; + list-style-type: decimal; +} + +@media screen { + + /* string content */ + + .str { + color: #ac9739; + } + + /* keyword */ + + .kwd { + color: #6679cc; + } + + /* comment */ + + .com { + color: #202746; + } + + /* type name */ + + .typ { + color: #3d8fd1; + } + + /* literal value */ + + .lit { + color: #c76b29; + } + + /* punctuation */ + + .pun { + color: #202746; + } + + /* lisp open bracket */ + + .opn { + color: #202746; + } + + /* lisp close bracket */ + + .clo { + color: #202746; + } + + /* markup tag name */ + + .tag { + color: #c94922; + } + + /* markup attribute name */ + + .atn { + color: #c76b29; + } + + /* markup attribute value */ + + .atv { + color: #22a2c9; + } + + /* declaration */ + + .dec { + color: #c76b29; + } + + /* variable name */ + + .var { + color: #c94922; + } + + /* function name */ + + .fun { + color: #3d8fd1; + } +}</style> +</head> +<body onload="prettyPrint()"> +<section> +<h1>AST code</h1> +<a name="1:1"><div class="section"><h4 class="noheading">1. </h4></a> +<p>This is the AST code. There's no important logic here, this is just accessors and constructors for the AST nodes +</p> + +</div> +<a name="1:2"><div class="section"><h4>2. The AST Interface - Node Types</h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Node Types <a href="ast.html#1:2">2</a>}</span> +<pre class="prettyprint lang-c"> +typedef struct ast_node ast_node_t; + +typedef enum { + // Expression nodes + AST_INTU32, + AST_INTU64, + AST_INTS32, + AST_INTS64, + AST_FLOAT, + AST_DOUBLE, + AST_STRING, + AST_CHAR, + AST_VAR, + AST_SUBSCRIPT, + AST_DIRECT_COMPONENT_SELECTION, + AST_INDIRECT_COMPONENT_SELECTION, + AST_FUNCTION_CALL, + AST_POSTFIX_INC, + AST_POSTFIX_DEC, + AST_UNARY_PLUS, + AST_UNARY_MINUS, + AST_LOGICAL_NOT, + AST_BITWISE_NOT, + AST_ADDRESS_OF, + AST_INDIRECTION, + AST_SIZEOF, + AST_PRE_INC, + AST_PRE_DEC, + AST_CAST, + AST_MUL, + AST_DIV, + AST_MOD, + AST_ADD, + AST_SUB, + AST_LEFT_SHIFT, + AST_RIGHT_SHIFT, + AST_LESS_THAN, + AST_GREATER_THAN, + AST_LESS_THAN_OR_EQUAL, + AST_GREATER_THAN_OR_EQUAL, + AST_EQUAL, + AST_NOT_EQUAL, + AST_BITWISE_AND, + AST_BITWISE_XOR, + AST_BITWISE_OR, + AST_LOGICAL_AND, + AST_LOGICAL_OR, + AST_CONDITIONAL, + AST_ASSIGN, + AST_ADD_ASSIGN, + AST_SUB_ASSIGN, + AST_MUL_ASSIGN, + AST_DIV_ASSIGN, + AST_MOD_ASSIGN, + AST_LEFT_SHIFT_ASSIGN, + AST_RIGHT_SHIFT_ASSIGN, + AST_AND_ASSIGN, + AST_XOR_ASSIGN, + AST_OR_ASSIGN, + AST_COMMA, + // Statement nodes + AST_EXPRESSION_STATEMENT, + AST_LABEL_STATEMENT, + AST_CASE_STATEMENT, + AST_DEFAULT_STATEMENT, + AST_COMPOUND_STATEMENT, + AST_IF_STATEMENT, + AST_WHILE_STATEMENT, + AST_DO_WHILE_STATEMENT, + AST_FOR_STATEMENT, + AST_GOTO_STATEMENT, + AST_CONTINUE_STATEMENT, + AST_BREAK_STATEMENT, + AST_RETURN_STATEMENT, + AST_SWITCH_STATEMENT, + AST_NULL_STATEMENT, + // Declaration nodes + AST_VAR_DECL, + AST_FUN_DECL, + AST_PARAM, + AST_FUN_DEF, + AST_STRUCT_DECL, + AST_UNION_DECL, + AST_ENUM_DECL, + AST_TYPEDEF, + AST_TYPE, + AST_MEMBER, + AST_ENUM_MEMBER, + // Translation unit + AST_TRANSLATION_UNIT +} ast_node_type_t; +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:15">15</a></p> +</div> +</div> +<a name="1:3"><div class="section"><h4>3. The AST Interface - Creating Nodes</h4></a> +<p>These functions create nodes for the AST. +</p> +<p>The order of functions here partly follows the order of the grammar rules from the bottom up, I.E primary -> postfix -> unary -> multiplicative -> additive -> relational -> equality -> assignment -> expression -> statement -> declaration. +</p> + +<div class="codeblock"> +<span class="codeblock_name">{Node Creation (Expression Nodes) <a href="ast.html#1:3">3</a>}</span> +<pre class="prettyprint lang-c"> +// Expression nodes (primary) +ast_node_t *ast_create_ints32_node(int32_t value, int line, int column); // 1 +ast_node_t *ast_create_ints64_node(int64_t value, int line, int column); // 1L +ast_node_t *ast_create_intu32_node(uint32_t value, int line, int column); // 1u +ast_node_t *ast_create_intu64_node(uint64_t value, int line, int column); // 1ul +ast_node_t *ast_create_float_node(float value, int line, int column); // 1.0f +ast_node_t *ast_create_double_node(double value, int line, int column); // 1.0 +ast_node_t *ast_create_string_node(char *value, int line, int column); // "string" +ast_node_t *ast_create_char_node(char value, int line, int column); // 'c' +ast_node_t *ast_create_var_node(char *value, int line, int column); // Variable +// Nothing needed for paren as the child can just be placed in the parent node directly +// Expression nodes (postfix) +ast_node_t *ast_create_subscript_node(ast_node_t *expr, ast_node_t *subscript, int line, int column); // expr[subscript] +ast_node_t *ast_create_direct_component_selection_node(ast_node_t *expr, char *component, int line, int column); // .component +ast_node_t *ast_create_indirect_component_selection_node(ast_node_t *expr, char *component, int line, int column); // -&gt;component +ast_node_t *ast_create_function_call_node(ast_node_t *expr, ast_node_t **args, size_t num_args, int line, int column); // expr(arg1, arg2, ...) +ast_node_t *ast_create_postfix_inc_node(ast_node_t *expr, int line, int column); // expr++ +ast_node_t *ast_create_postfix_dec_node(ast_node_t *expr, int line, int column); // expr-- +// Expression nodes (unary) +ast_node_t *ast_create_unary_plus_node(ast_node_t *expr, int line, int column); // +expr +ast_node_t *ast_create_unary_minus_node(ast_node_t *expr, int line, int column); // -expr +ast_node_t *ast_create_logical_not_node(ast_node_t *expr, int line, int column); // !expr +ast_node_t *ast_create_bitwise_not_node(ast_node_t *expr, int line, int column); // ~expr +ast_node_t *ast_create_address_of_node(ast_node_t *expr, int line, int column); // &amp;expr +ast_node_t *ast_create_indirection_node(ast_node_t *expr, int line, int column); // *expr +ast_node_t *ast_create_sizeof_node(ast_node_t *expr, int line, int column); // sizeof(expr) +ast_node_t *ast_create_pre_inc_node(ast_node_t *expr, int line, int column); // ++expr +ast_node_t *ast_create_pre_dec_node(ast_node_t *expr, int line, int column); // --expr +// Expression nodes (cast) +ast_node_t *ast_create_cast_node(ast_node_t *type, ast_node_t *expr, int line, int column); // (type)expr +// Expression nodes (multiplicative) +ast_node_t *ast_create_mul_node(ast_node_t *left, ast_node_t *right, int line, int column); // left * right +ast_node_t *ast_create_div_node(ast_node_t *left, ast_node_t *right, int line, int column); // left / right +ast_node_t *ast_create_mod_node(ast_node_t *left, ast_node_t *right, int line, int column); // left % right +// Expression nodes (additive) +ast_node_t *ast_create_add_node(ast_node_t *left, ast_node_t *right, int line, int column); // left + right +ast_node_t *ast_create_sub_node(ast_node_t *left, ast_node_t *right, int line, int column); // left - right +// Expression nodes (shift) +ast_node_t *ast_create_left_shift_node(ast_node_t *left, ast_node_t *right, int line, int column); // left &lt;&lt; right +ast_node_t *ast_create_right_shift_node(ast_node_t *left, ast_node_t *right, int line, int column); // left &gt;&gt; right +// Expression nodes (relational) +ast_node_t *ast_create_less_than_node(ast_node_t *left, ast_node_t *right, int line, int column); // left &lt; right +ast_node_t *ast_create_greater_than_node(ast_node_t *left, ast_node_t *right, int line, int column); // left &gt; right +ast_node_t *ast_create_less_than_or_equal_node(ast_node_t *left, ast_node_t *right, int line, int column); // left &lt;= right +ast_node_t *ast_create_greater_than_or_equal_node(ast_node_t *left, ast_node_t *right, int line, int column); // left &gt;= right +// Expression nodes (equality) +ast_node_t *ast_create_equal_node(ast_node_t *left, ast_node_t *right, int line, int column); // left == right +ast_node_t *ast_create_not_equal_node(ast_node_t *left, ast_node_t *right, int line, int column); // left != right +// Expression nodes (bitwise and) +ast_node_t *ast_create_bitwise_and_node(ast_node_t *left, ast_node_t *right, int line, int column); // left &amp; right +// Expression nodes (bitwise xor) +ast_node_t *ast_create_bitwise_xor_node(ast_node_t *left, ast_node_t *right, int line, int column); // left ^ right +// Expression nodes (bitwise or) +ast_node_t *ast_create_bitwise_or_node(ast_node_t *left, ast_node_t *right, int line, int column); // left | right +// Expression nodes (logical and) +ast_node_t *ast_create_logical_and_node(ast_node_t *left, ast_node_t *right, int line, int column); // left &amp;&amp; right +// Expression nodes (logical or) +ast_node_t *ast_create_logical_or_node(ast_node_t *left, ast_node_t *right, int line, int column); // left || right +// Expression nodes (conditional) +ast_node_t *ast_create_conditional_node(ast_node_t *condition, ast_node_t *true_expr, ast_node_t *false_expr, int line, int column); // condition ? true_expr : false_expr +// Expression nodes (assignment) +ast_node_t *ast_create_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left = right +ast_node_t *ast_create_add_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left += right +ast_node_t *ast_create_sub_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left -= right +ast_node_t *ast_create_mul_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left *= right +ast_node_t *ast_create_div_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left /= right +ast_node_t *ast_create_mod_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left %= right +ast_node_t *ast_create_left_shift_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left &lt;&lt;= right +ast_node_t *ast_create_right_shift_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left &gt;&gt;= right +ast_node_t *ast_create_and_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left &amp;= right +ast_node_t *ast_create_xor_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left ^= right +ast_node_t *ast_create_or_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left |= right +// Expression nodes (comma) +ast_node_t *ast_create_comma_node(ast_node_t *left, ast_node_t *right, int line, int column); // left, right +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:15">15</a></p> +</div> +</div> +<a name="1:4"><div class="section"><h4 class="noheading">4. </h4></a> +<p>Here we define functions for creating statement nodes. +</p> + +<div class="codeblock"> +<span class="codeblock_name">{Node Creation (Statement Nodes) <a href="ast.html#1:4">4</a>}</span> +<pre class="prettyprint lang-c"> +// Statement nodes (expression) +ast_node_t *ast_create_expression_statement_node(ast_node_t *expr); // expr; +// Statement nodes (label) +ast_node_t *ast_create_label_statement_node(char *label, int line, int column); // label: +ast_node_t *ast_create_case_statement_node(ast_node_t *expr, int line, int column); // case expr: +ast_node_t *ast_create_default_statement_node(int line, int column); // default: +// Statement nodes (compound) +ast_node_t *ast_create_compound_statement_node(ast_node_t **decls_and_stmts, size_t num_decls_and_stmts, int line, int column); // { decls_and_stmts } +// Statement nodes (conditional) +ast_node_t *ast_create_if_statement_node(ast_node_t *condition, ast_node_t *true_stmt, ast_node_t *false_stmt, int line, int column); // if (condition) true_stmt else false_stmt +// Statement nodes (iteration) +ast_node_t *ast_create_while_statement_node(ast_node_t *condition, ast_node_t *stmt, int line, int column); // while (condition) stmt +ast_node_t *ast_create_do_while_statement_node(ast_node_t *stmt, ast_node_t *condition, int line, int column); // do stmt while (condition) +ast_node_t *ast_create_for_statement_node(ast_node_t *init, ast_node_t *condition, ast_node_t *update, ast_node_t *stmt, int line, int column); // for (init; condition; update) stmt +// Statement nodes (jump) +ast_node_t *ast_create_goto_statement_node(char *label, int line, int column); // goto label; +ast_node_t *ast_create_continue_statement_node(int line, int column); // continue; +ast_node_t *ast_create_break_statement_node(int line, int column); // break; +ast_node_t *ast_create_return_statement_node(ast_node_t *expr, int line, int column); // return expr; +// Statement nodes (multiway branch) +ast_node_t *ast_create_switch_statement_node(ast_node_t *expr, ast_node_t *stmt, int line, int column); // switch (expr) stmt +// Statement nodes (null) +ast_node_t *ast_create_null_statement_node(int line, int column); // ; +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:15">15</a></p> +</div> +</div> +<a name="1:5"><div class="section"><h4 class="noheading">5. </h4></a> +<p>Here we define functions for creating declaration nodes. Types are passed as a raw list of tokens, which will be used in the semantic analysis phase to build a type. In this way, we're kind of offsetting type parsing. +</p> +<p>An example call for a declaration would be <code>ast_node_t *type = ast_create_type_node((token_t *[]){ptr to TOK_VOLATILE, ptr to TOK_CONST, ptr to TOK_INT}, 3);</code>, <code>ast_node_t *decl = ast_create_var_decl_node(type, "x");</code>. +</p> +<p>A special AST node is created for parameters, struct/union members, and enum members. The enum member node can hold a value, but the others are just for the type. +A special AST node also exists for types. +</p> + +<div class="codeblock"> +<span class="codeblock_name">{Node Creation (Declaration Nodes) <a href="ast.html#1:5">5</a>}</span> +<pre class="prettyprint lang-c"> +// Declaration nodes (simple) +ast_node_t *ast_create_var_decl_node(ast_node_t *type, char *id, int line, int column); // type id +ast_node_t *ast_create_fun_decl_node(ast_node_t *type, char *id, ast_node_t **params, size_t num_params, int line, int column); // type id(params) +// Declaration nodes (parameter) +ast_node_t *ast_create_param_node(ast_node_t *type, char *id, int line, int column); // type id +// Declaration nodes (function) +ast_node_t *ast_create_fun_def_node(ast_node_t *type, char *id, ast_node_t **params, size_t num_params, ast_node_t *stmt, int line, int column); // type id(params) stmt +// Declaration nodes (struct) +ast_node_t *ast_create_struct_decl_node(char *id, ast_node_t **members, size_t num_members, int line, int column); // struct id { members } (reuses param node for members) +// Declaration nodes (union) +ast_node_t *ast_create_union_decl_node(char *id, ast_node_t **members, size_t num_members, int line, int column); // union id { members } (reuses param node for members) +// Declaration nodes (enum) +ast_node_t *ast_create_enum_decl_node(char *id, ast_node_t **enums, size_t num_enums, int line, int column); // enum id { enums } +// Declaration nodes (Typedef) +ast_node_t *ast_create_typedef_node(ast_node_t *type, char *id, int line, int column); // typedef type id +// Types/members +ast_node_t *ast_create_type_node(token_t *type[], size_t num_type, int line, int column); // type +ast_node_t *ast_create_member_node(ast_node_t *type, char *id, int line, int column); // type id +ast_node_t *ast_create_enum_member_node(char *id, ast_node_t *value, int line, int column); // id = value +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:15">15</a></p> +</div> +</div> +<a name="1:6"><div class="section"><h4>6. The AST Interface - Translation Unit</h4></a> +<p>The translation unit is the root of the AST. It's a list of nodes, which can be declarations or statements. This is the only function that will be called from the parser. +</p> + +<div class="codeblock"> +<span class="codeblock_name">{Node Creation (Translation Unit) <a href="ast.html#1:6">6</a>}</span> +<pre class="prettyprint lang-c"> +ast_node_t *ast_create_translation_unit(ast_node_t **nodes, size_t num_nodes, int line, int column); +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:15">15</a></p> +</div> +</div> +<a name="1:7"><div class="section"><h4>7. The AST Interface - Destroying Nodes</h4></a> +<p>A single function is defined to destroy an AST node and all its children. +</p> + +<div class="codeblock"> +<span class="codeblock_name">{Node Destruction <a href="ast.html#1:7">7</a>}</span> +<pre class="prettyprint lang-c"> +void ast_destroy_node(ast_node_t *node); +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:15">15</a></p> +</div> +</div> +<a name="1:8"><div class="section"><h4>8. The AST Interface - Getting Node Information</h4></a> +<p>These functions get information from the AST nodes. They will do on-the-fly type checking to ensure the node is the correct type, so we need to have separate functions for each type of node. +</p> + +</div> +<a name="1:9"><div class="section"><h4 class="noheading">9. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Node Information (General) <a href="ast.html#1:9">9</a>}</span> +<pre class="prettyprint lang-c"> +ast_node_type_t ast_get_node_type(ast_node_t *node); +int ast_get_node_line(ast_node_t *node); +int ast_get_node_column(ast_node_t *node); +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:15">15</a></p> +</div> +</div> +<a name="1:10"><div class="section"><h4 class="noheading">10. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Node Information (Expression Nodes) <a href="ast.html#1:10">10</a>}</span> +<pre class="prettyprint lang-c"> +// Expression nodes (primary) +int64_t ast_get_int_value(ast_node_t *node); +double ast_get_double_value(ast_node_t *node); +char *ast_get_string_value(ast_node_t *node); +char ast_get_char_value(ast_node_t *node); +char *ast_get_var_value(ast_node_t *node); +// Expression nodes (postfix) +ast_node_t *ast_get_subscript_expr(ast_node_t *node); +ast_node_t *ast_get_subscript_idx(ast_node_t *node); +char *ast_get_component(ast_node_t *node); +ast_node_t *ast_get_function_call_expr(ast_node_t *node); +ast_node_t **ast_get_function_call_args(ast_node_t *node, size_t *num_args); +ast_node_t *ast_get_postfix_expr(ast_node_t *node); +// Expression nodes (unary) +ast_node_t *ast_get_unary_expr(ast_node_t *node); +// Expression nodes (cast) +ast_node_t *ast_get_cast_type(ast_node_t *node); +ast_node_t *ast_get_cast_expr(ast_node_t *node); +// Expression nodes (binary) +ast_node_t *ast_get_left_expr(ast_node_t *node); +ast_node_t *ast_get_right_expr(ast_node_t *node); +// Expression nodes (conditional) +ast_node_t *ast_get_conditional_condition(ast_node_t *node); +ast_node_t *ast_get_conditional_true_expr(ast_node_t *node); +ast_node_t *ast_get_conditional_false_expr(ast_node_t *node); +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:15">15</a></p> +</div> +</div> +<a name="1:11"><div class="section"><h4 class="noheading">11. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Node Information (Statement Nodes) <a href="ast.html#1:11">11</a>}</span> +<pre class="prettyprint lang-c"> +// Statement nodes (expression) +ast_node_t *ast_get_expression_statement_expr(ast_node_t *node); +// Statement nodes (label) +char *ast_get_label_statement_label(ast_node_t *node); // label +ast_node_t *ast_get_case_statement_expr(ast_node_t *node); // expr +// Statement nodes (compound) +ast_node_t **ast_get_compound_statement_contents(ast_node_t *node, size_t *num_contents); // decls_and_stmts +// Statement nodes (conditional) +ast_node_t *ast_get_if_statement_condition(ast_node_t *node); // condition +ast_node_t *ast_get_if_statement_true_stmt(ast_node_t *node); // true_stmt +ast_node_t *ast_get_if_statement_false_stmt(ast_node_t *node); // false_stmt +// Statement nodes (iteration) +ast_node_t *ast_get_iteration_statement_condition(ast_node_t *node); // condition +ast_node_t *ast_get_iteration_statement_stmt(ast_node_t *node); // stmt +ast_node_t *ast_get_for_statement_init(ast_node_t *node); // init +ast_node_t *ast_get_for_statement_update(ast_node_t *node); // update +// Statement nodes (jump) +char *ast_get_goto_statement_label(ast_node_t *node); // label +// Statement nodes (multiway branch) +ast_node_t *ast_get_switch_statement_expr(ast_node_t *node); // expr +ast_node_t *ast_get_switch_statement_stmt(ast_node_t *node); // stmt +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:15">15</a></p> +</div> +</div> +<a name="1:12"><div class="section"><h4 class="noheading">12. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Node Information (Declaration Nodes) <a href="ast.html#1:12">12</a>}</span> +<pre class="prettyprint lang-c"> +// Declaration nodes (simple) +ast_node_t *ast_get_var_decl_type(ast_node_t *node); +char *ast_get_var_decl_id(ast_node_t *node); +ast_node_t *ast_get_fun_decl_type(ast_node_t *node); +char *ast_get_fun_decl_id(ast_node_t *node); +ast_node_t **ast_get_fun_decl_params(ast_node_t *node, size_t *num_params); +// Declaration nodes (parameter) +ast_node_t *ast_get_param_type(ast_node_t *node); +char *ast_get_param_id(ast_node_t *node); +// Declaration nodes (function) +ast_node_t *ast_get_fun_def_type(ast_node_t *node); +char *ast_get_fun_def_id(ast_node_t *node); +ast_node_t **ast_get_fun_def_params(ast_node_t *node, size_t *num_params); +ast_node_t *ast_get_fun_def_stmt(ast_node_t *node); +// Declaration nodes (struct) +char *ast_get_struct_decl_id(ast_node_t *node); +ast_node_t **ast_get_struct_decl_members(ast_node_t *node, size_t *num_members); +// Declaration nodes (union) +char *ast_get_union_decl_id(ast_node_t *node); +ast_node_t **ast_get_union_decl_members(ast_node_t *node, size_t *num_members); +// Declaration nodes (enum) +char *ast_get_enum_decl_id(ast_node_t *node); +ast_node_t **ast_get_enum_decl_enums(ast_node_t *node, size_t *num_enums); +// Declaration nodes (Typedef) +ast_node_t *ast_get_typedef_type(ast_node_t *node); +char *ast_get_typedef_id(ast_node_t *node); +// Types/members +token_t **ast_get_type(ast_node_t *node, size_t *num_type); +ast_node_t *ast_get_member_type(ast_node_t *node); +char *ast_get_member_id(ast_node_t *node); +ast_node_t *ast_get_enum_member_expr(ast_node_t *node); +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:15">15</a></p> +</div> +</div> +<a name="1:13"><div class="section"><h4 class="noheading">13. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Node Information (Translation Unit) <a href="ast.html#1:13">13</a>}</span> +<pre class="prettyprint lang-c"> +ast_node_t **ast_get_translation_unit(ast_node_t *node, size_t *num_nodes); +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:15">15</a></p> +</div> +</div> +<a name="1:14"><div class="section"><h4 class="noheading">14. </h4></a> +<p>Having seperate calls for each type makes it very difficult to mess up the tree structure in the parser. +</p> + +</div> +<a name="1:15"><div class="section"><h4 class="noheading">15. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{<strong>ast.h</strong> <a href="ast.html#1:15">15</a>}</span> +<pre class="prettyprint lang-c"> +#ifndef AST_H +#define AST_H +#include "token.h" +#include &lt;stddef.h&gt; +#include &lt;stdint.h&gt; +<span class="nocode pln">{Node Types, <a href="ast.html#1:2">2</a>}</span> +<span class="nocode pln">{Node Creation (Expression Nodes), <a href="ast.html#1:3">3</a>}</span> +<span class="nocode pln">{Node Creation (Statement Nodes), <a href="ast.html#1:4">4</a>}</span> +<span class="nocode pln">{Node Creation (Declaration Nodes), <a href="ast.html#1:5">5</a>}</span> +<span class="nocode pln">{Node Creation (Translation Unit), <a href="ast.html#1:6">6</a>}</span> +<span class="nocode pln">{Node Destruction, <a href="ast.html#1:7">7</a>}</span> +<span class="nocode pln">{Node Information (General), <a href="ast.html#1:9">9</a>}</span> +<span class="nocode pln">{Node Information (Expression Nodes), <a href="ast.html#1:10">10</a>}</span> +<span class="nocode pln">{Node Information (Statement Nodes), <a href="ast.html#1:11">11</a>}</span> +<span class="nocode pln">{Node Information (Declaration Nodes), <a href="ast.html#1:12">12</a>}</span> +<span class="nocode pln">{Node Information (Translation Unit), <a href="ast.html#1:13">13</a>}</span> +#endif +</pre> + + + +</div> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Common Node Structure <a href="ast.html#1:15">15</a>}</span> +<pre class="prettyprint lang-c"> +#define AST_MAGIC 0x4153544E4F44ULL // "ASTNOD" + +struct ast_node { + long magic; + int line; + int column; + int hasdata; + short kind; + long opt_data[0]; +}; + +static void* ast_get_data(ast_node_t *node) +{ + assert(node-&gt;magic == AST_MAGIC); + assert(node-&gt;hasdata); + return node-&gt;opt_data; +} + +ast_node_type_t ast_get_node_type(ast_node_t *node) +{ + assert(node-&gt;magic == AST_MAGIC); + return node-&gt;kind; +} + +int ast_get_node_line(ast_node_t *node) +{ + assert(node-&gt;magic == AST_MAGIC); + return node-&gt;line; +} + +int ast_get_node_column(ast_node_t *node) +{ + assert(node-&gt;magic == AST_MAGIC); + return node-&gt;column; +} + +static ast_node_t *ast_create_node(ast_node_type_t kind, int line, int column, size_t data_size) +{ + ast_node_t *node = malloc(sizeof(ast_node_t) + data_size); + node-&gt;magic = AST_MAGIC; + node-&gt;line = line; + node-&gt;column = column; + node-&gt;hasdata = data_size &gt; 0; + node-&gt;kind = kind; + return node; +} +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:16"><div class="section"><h4 class="noheading">16. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Primary) <a href="ast.html#1:16">16</a>}</span> +<pre class="prettyprint lang-c"> +struct ast_int_node { + int64_t value; +}; + +ast_node_t *ast_create_intu32_node(uint32_t value, int line, int column) +{ + ast_node_t *node = + ast_create_node(AST_INTU32, line, column, sizeof(struct ast_int_node)); + struct ast_int_node *data = ast_get_data(node); + data-&gt;value = value; + return node; +} + +ast_node_t *ast_create_ints32_node(int32_t value, int line, int column) +{ + ast_node_t *node = + ast_create_node(AST_INTS32, line, column, sizeof(struct ast_int_node)); + struct ast_int_node *data = ast_get_data(node); + data-&gt;value = value; + return node; +} + +ast_node_t *ast_create_intu64_node(uint64_t value, int line, int column) +{ + ast_node_t *node = + ast_create_node(AST_INTU64, line, column, sizeof(struct ast_int_node)); + struct ast_int_node *data = ast_get_data(node); + data-&gt;value = value; + return node; +} + +ast_node_t *ast_create_ints64_node(int64_t value, int line, int column) +{ + ast_node_t *node = + ast_create_node(AST_INTS64, line, column, sizeof(struct ast_int_node)); + struct ast_int_node *data = ast_get_data(node); + data-&gt;value = value; + return node; +} + +int64_t ast_get_int_value(ast_node_t *node) { + assert(ast_get_node_type(node) == AST_INTU32 || ast_get_node_type(node) == AST_INTS32 || ast_get_node_type(node) == AST_INTU64 || ast_get_node_type(node) == AST_INTS64); + struct ast_int_node *data = ast_get_data(node); + return data-&gt;value; +} + +struct ast_double_node { + double value; +}; + +struct ast_float_node { + float value; +}; + +ast_node_t *ast_create_float_node(float value, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_FLOAT, line, column, sizeof(struct ast_float_node)); + struct ast_float_node *data = ast_get_data(node); + data-&gt;value = value; + return node; +} + +float ast_get_float_value(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_FLOAT); + struct ast_float_node *data = ast_get_data(node); + return data-&gt;value; +} + +ast_node_t *ast_create_double_node(double value, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_DOUBLE, line, column, sizeof(struct ast_double_node)); + struct ast_double_node *data = ast_get_data(node); + data-&gt;value = value; + return node; +} + +double ast_get_double_value(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_DOUBLE); + struct ast_double_node *data = ast_get_data(node); + return data-&gt;value; +} + +struct ast_string_node { + char *value; +}; + +ast_node_t *ast_create_string_node(char *value, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_STRING, line, column, sizeof(struct ast_string_node)); + struct ast_string_node *data = ast_get_data(node); + data-&gt;value = value; // We don't duplicate here because the string is in the shared string table + return node; +} + +char *ast_get_string_value(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_STRING); + struct ast_string_node *data = ast_get_data(node); + return data-&gt;value; +} + +struct ast_char_node { + char value; +}; + +ast_node_t *ast_create_char_node(char value, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_CHAR, line, column, sizeof(struct ast_char_node)); + struct ast_char_node *data = ast_get_data(node); + data-&gt;value = value; + return node; +} + +char ast_get_char_value(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CHAR); + struct ast_char_node *data = ast_get_data(node); + return data-&gt;value; +} + +ast_node_t *ast_create_var_node(char *value, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_VAR, line, column, sizeof(struct ast_string_node)); + struct ast_string_node *data = ast_get_data(node); + data-&gt;value = value; // We don't duplicate here because the string is in the shared string table + return node; +} + +char *ast_get_var_value(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_VAR); + struct ast_string_node *data = ast_get_data(node); + return data-&gt;value; +} +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:17"><div class="section"><h4 class="noheading">17. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Postfix) <a href="ast.html#1:17">17</a>}</span> +<pre class="prettyprint lang-c"> +struct ast_subscript_node { + ast_node_t *expr; + ast_node_t *subscript; +}; + +ast_node_t *ast_create_subscript_node(ast_node_t *expr, ast_node_t *subscript, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_SUBSCRIPT, line, column, sizeof(struct ast_subscript_node)); + struct ast_subscript_node *data = ast_get_data(node); + data-&gt;expr = expr; + data-&gt;subscript = subscript; + return node; +} + +ast_node_t *ast_get_subscript_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_SUBSCRIPT); + struct ast_subscript_node *data = ast_get_data(node); + return data-&gt;expr; +} + +ast_node_t *ast_get_subscript_idx(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_SUBSCRIPT); + struct ast_subscript_node *data = ast_get_data(node); + return data-&gt;subscript; +} + +struct ast_component_selection_node { + ast_node_t *expr; + char *component; +}; + +ast_node_t *ast_create_direct_component_selection_node(ast_node_t *expr, char *component, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_DIRECT_COMPONENT_SELECTION, line, column, sizeof(struct ast_component_selection_node)); + struct ast_component_selection_node *data = ast_get_data(node); + data-&gt;expr = expr; + data-&gt;component = component; + return node; +} + +char *ast_get_component(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_DIRECT_COMPONENT_SELECTION); + struct ast_component_selection_node *data = ast_get_data(node); + return data-&gt;component; +} + +ast_node_t *ast_get_component_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_DIRECT_COMPONENT_SELECTION); + struct ast_component_selection_node *data = ast_get_data(node); + return data-&gt;expr; +} + +ast_node_t *ast_create_indirect_component_selection_node(ast_node_t *expr, char *component, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_INDIRECT_COMPONENT_SELECTION, line, column, sizeof(struct ast_component_selection_node)); + struct ast_component_selection_node *data = ast_get_data(node); + data-&gt;expr = expr; + data-&gt;component = component; + return node; +} + +struct ast_function_call_node { + ast_node_t *expr; + ast_node_t **args; + size_t num_args; +}; + +ast_node_t *ast_create_function_call_node(ast_node_t *expr, ast_node_t **args, size_t num_args, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_FUNCTION_CALL, line, column, sizeof(struct ast_function_call_node)); + struct ast_function_call_node *data = ast_get_data(node); + data-&gt;expr = expr; + data-&gt;args = args; + data-&gt;num_args = num_args; + return node; +} + +ast_node_t *ast_get_function_call_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_FUNCTION_CALL); + struct ast_function_call_node *data = ast_get_data(node); + return data-&gt;expr; +} + +ast_node_t **ast_get_function_call_args(ast_node_t *node, size_t *num_args) +{ + assert(ast_get_node_type(node) == AST_FUNCTION_CALL); + struct ast_function_call_node *data = ast_get_data(node); + *num_args = data-&gt;num_args; + return data-&gt;args; +} + +ast_node_t *ast_create_postfix_inc_node(ast_node_t *expr, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_POSTFIX_INC, line, column, sizeof(ast_node_t *)); + ast_node_t **data = ast_get_data(node); + *data = expr; + return node; +} + +ast_node_t *ast_create_postfix_dec_node(ast_node_t *expr, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_POSTFIX_DEC, line, column, sizeof(ast_node_t *)); + ast_node_t **data = ast_get_data(node); + *data = expr; + return node; +} + +ast_node_t *ast_get_postfix_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_POSTFIX_INC || ast_get_node_type(node) == AST_POSTFIX_DEC); + ast_node_t **data = ast_get_data(node); + return *data; +} +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:18"><div class="section"><h4 class="noheading">18. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Unary/Cast) <a href="ast.html#1:18">18</a>}</span> +<pre class="prettyprint lang-c"> + +#define AST_CREATE_UNARY_NODE(NODE_TYPE, NODE_NAME) \ +ast_node_t *ast_create_##NODE_NAME##_node(ast_node_t *expr, int line, int column) \ +{ \ + ast_node_t *node = ast_create_node(NODE_TYPE, line, column, sizeof(ast_node_t *)); \ + ast_node_t **data = ast_get_data(node); \ + *data = expr; \ + return node; \ +} + +AST_CREATE_UNARY_NODE(AST_UNARY_PLUS, unary_plus) +AST_CREATE_UNARY_NODE(AST_UNARY_MINUS, unary_minus) +AST_CREATE_UNARY_NODE(AST_LOGICAL_NOT, logical_not) +AST_CREATE_UNARY_NODE(AST_BITWISE_NOT, bitwise_not) +AST_CREATE_UNARY_NODE(AST_ADDRESS_OF, address_of) +AST_CREATE_UNARY_NODE(AST_INDIRECTION, indirection) +AST_CREATE_UNARY_NODE(AST_SIZEOF, sizeof) +AST_CREATE_UNARY_NODE(AST_PRE_INC, pre_inc) +AST_CREATE_UNARY_NODE(AST_PRE_DEC, pre_dec) + +ast_node_t *ast_create_cast_node(ast_node_t *type, ast_node_t *expr, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_CAST, line, column, 2 * sizeof(ast_node_t *)); + ast_node_t **data = ast_get_data(node); + data[0] = type; + data[1] = expr; + return node; +} + +ast_node_t *ast_get_unary_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_UNARY_PLUS || ast_get_node_type(node) == AST_UNARY_MINUS || ast_get_node_type(node) == AST_LOGICAL_NOT || ast_get_node_type(node) == AST_BITWISE_NOT || ast_get_node_type(node) == AST_ADDRESS_OF || ast_get_node_type(node) == AST_INDIRECTION || ast_get_node_type(node) == AST_SIZEOF || ast_get_node_type(node) == AST_PRE_INC || ast_get_node_type(node) == AST_PRE_DEC || ast_get_node_type(node) == AST_CAST); + ast_node_t **data = ast_get_data(node); + return data[0]; +} + +ast_node_t *ast_get_cast_type(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CAST); + ast_node_t **data = ast_get_data(node); + return data[0]; +} + +ast_node_t *ast_get_cast_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CAST); + ast_node_t **data = ast_get_data(node); + return data[1]; +} + +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:19"><div class="section"><h4 class="noheading">19. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Binary/Assign/Comma) <a href="ast.html#1:19">19</a>}</span> +<pre class="prettyprint lang-c"> +struct ast_binary_node { + ast_node_t *left; + ast_node_t *right; +}; + +// Macro to generate binary AST node creation functions +#define AST_CREATE_BINARY_NODE(NODE_TYPE, NODE_NAME) \ +ast_node_t *ast_create_##NODE_NAME##_node(ast_node_t *left, ast_node_t *right, int line, int column) \ +{ \ + ast_node_t *node = ast_create_node(NODE_TYPE, line, column, sizeof(struct ast_binary_node)); \ + struct ast_binary_node *data = ast_get_data(node); \ + data-&gt;left = left; \ + data-&gt;right = right; \ + return node; \ +} + +AST_CREATE_BINARY_NODE(AST_MUL, mul) +AST_CREATE_BINARY_NODE(AST_DIV, div) +AST_CREATE_BINARY_NODE(AST_MOD, mod) +AST_CREATE_BINARY_NODE(AST_ADD, add) +AST_CREATE_BINARY_NODE(AST_SUB, sub) +AST_CREATE_BINARY_NODE(AST_LEFT_SHIFT, left_shift) +AST_CREATE_BINARY_NODE(AST_RIGHT_SHIFT, right_shift) +AST_CREATE_BINARY_NODE(AST_LESS_THAN, less_than) +AST_CREATE_BINARY_NODE(AST_GREATER_THAN, greater_than) +AST_CREATE_BINARY_NODE(AST_LESS_THAN_OR_EQUAL, less_than_or_equal) +AST_CREATE_BINARY_NODE(AST_GREATER_THAN_OR_EQUAL, greater_than_or_equal) +AST_CREATE_BINARY_NODE(AST_EQUAL, equal) +AST_CREATE_BINARY_NODE(AST_NOT_EQUAL, not_equal) +AST_CREATE_BINARY_NODE(AST_BITWISE_AND, bitwise_and) +AST_CREATE_BINARY_NODE(AST_BITWISE_XOR, bitwise_xor) +AST_CREATE_BINARY_NODE(AST_BITWISE_OR, bitwise_or) +AST_CREATE_BINARY_NODE(AST_LOGICAL_AND, logical_and) +AST_CREATE_BINARY_NODE(AST_LOGICAL_OR, logical_or) +AST_CREATE_BINARY_NODE(AST_ASSIGN, assign) +AST_CREATE_BINARY_NODE(AST_ADD_ASSIGN, add_assign) +AST_CREATE_BINARY_NODE(AST_SUB_ASSIGN, sub_assign) +AST_CREATE_BINARY_NODE(AST_MUL_ASSIGN, mul_assign) +AST_CREATE_BINARY_NODE(AST_DIV_ASSIGN, div_assign) +AST_CREATE_BINARY_NODE(AST_MOD_ASSIGN, mod_assign) +AST_CREATE_BINARY_NODE(AST_LEFT_SHIFT_ASSIGN, left_shift_assign) +AST_CREATE_BINARY_NODE(AST_RIGHT_SHIFT_ASSIGN, right_shift_assign) +AST_CREATE_BINARY_NODE(AST_AND_ASSIGN, bitwise_and_assign) +AST_CREATE_BINARY_NODE(AST_XOR_ASSIGN, bitwise_xor_assign) +AST_CREATE_BINARY_NODE(AST_OR_ASSIGN, bitwise_or_assign) +AST_CREATE_BINARY_NODE(AST_COMMA, comma) + +ast_node_t *ast_get_left_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_MUL || ast_get_node_type(node) == AST_DIV || ast_get_node_type(node) == AST_MOD + || ast_get_node_type(node) == AST_ADD || ast_get_node_type(node) == AST_SUB || ast_get_node_type(node) == AST_LEFT_SHIFT + || ast_get_node_type(node) == AST_RIGHT_SHIFT || ast_get_node_type(node) == AST_LESS_THAN || ast_get_node_type(node) == AST_GREATER_THAN + || ast_get_node_type(node) == AST_LESS_THAN_OR_EQUAL || ast_get_node_type(node) == AST_GREATER_THAN_OR_EQUAL + || ast_get_node_type(node) == AST_EQUAL || ast_get_node_type(node) == AST_NOT_EQUAL + || ast_get_node_type(node) == AST_BITWISE_AND || ast_get_node_type(node) == AST_BITWISE_XOR || ast_get_node_type(node) == AST_BITWISE_OR + || ast_get_node_type(node) == AST_LOGICAL_AND || ast_get_node_type(node) == AST_LOGICAL_OR || ast_get_node_type(node) == AST_ASSIGN + || ast_get_node_type(node) == AST_ADD_ASSIGN || ast_get_node_type(node) == AST_SUB_ASSIGN || ast_get_node_type(node) == AST_MUL_ASSIGN || ast_get_node_type(node) == AST_DIV_ASSIGN + || ast_get_node_type(node) == AST_MOD_ASSIGN || ast_get_node_type(node) == AST_LEFT_SHIFT_ASSIGN || ast_get_node_type(node) == AST_RIGHT_SHIFT_ASSIGN || ast_get_node_type(node) == AST_AND_ASSIGN + || ast_get_node_type(node) == AST_XOR_ASSIGN || ast_get_node_type(node) == AST_OR_ASSIGN || ast_get_node_type(node) == AST_COMMA); + struct ast_binary_node *data = ast_get_data(node); + return data-&gt;left; +} + +ast_node_t *ast_get_right_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_MUL || ast_get_node_type(node) == AST_DIV || ast_get_node_type(node) == AST_MOD + || ast_get_node_type(node) == AST_ADD || ast_get_node_type(node) == AST_SUB || ast_get_node_type(node) == AST_LEFT_SHIFT + || ast_get_node_type(node) == AST_RIGHT_SHIFT || ast_get_node_type(node) == AST_LESS_THAN || ast_get_node_type(node) == AST_GREATER_THAN + || ast_get_node_type(node) == AST_LESS_THAN_OR_EQUAL || ast_get_node_type(node) == AST_GREATER_THAN_OR_EQUAL + || ast_get_node_type(node) == AST_EQUAL || ast_get_node_type(node) == AST_NOT_EQUAL + || ast_get_node_type(node) == AST_BITWISE_AND || ast_get_node_type(node) == AST_BITWISE_XOR || ast_get_node_type(node) == AST_BITWISE_OR + || ast_get_node_type(node) == AST_LOGICAL_AND || ast_get_node_type(node) == AST_LOGICAL_OR || ast_get_node_type(node) == AST_ASSIGN + || ast_get_node_type(node) == AST_ADD_ASSIGN || ast_get_node_type(node) == AST_SUB_ASSIGN || ast_get_node_type(node) == AST_MUL_ASSIGN || ast_get_node_type(node) == AST_DIV_ASSIGN + || ast_get_node_type(node) == AST_MOD_ASSIGN || ast_get_node_type(node) == AST_LEFT_SHIFT_ASSIGN || ast_get_node_type(node) == AST_RIGHT_SHIFT_ASSIGN || ast_get_node_type(node) == AST_AND_ASSIGN + || ast_get_node_type(node) == AST_XOR_ASSIGN || ast_get_node_type(node) == AST_OR_ASSIGN || ast_get_node_type(node) == AST_COMMA); + struct ast_binary_node *data = ast_get_data(node); + return data-&gt;right; +} + +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:20"><div class="section"><h4 class="noheading">20. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Conditional) <a href="ast.html#1:20">20</a>}</span> +<pre class="prettyprint lang-c"> +struct ast_conditional_node { + ast_node_t *condition; + ast_node_t *true_expr; + ast_node_t *false_expr; +}; + +ast_node_t *ast_create_conditional_node(ast_node_t *condition, ast_node_t *true_expr, ast_node_t *false_expr, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_CONDITIONAL, line, column, sizeof(struct ast_conditional_node)); + struct ast_conditional_node *data = ast_get_data(node); + data-&gt;condition = condition; + data-&gt;true_expr = true_expr; + data-&gt;false_expr = false_expr; + return node; +} + +ast_node_t *ast_get_conditional_condition(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CONDITIONAL); + struct ast_conditional_node *data = ast_get_data(node); + return data-&gt;condition; +} + +ast_node_t *ast_get_conditional_true_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CONDITIONAL); + struct ast_conditional_node *data = ast_get_data(node); + return data-&gt;true_expr; +} + +ast_node_t *ast_get_conditional_false_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CONDITIONAL); + struct ast_conditional_node *data = ast_get_data(node); + return data-&gt;false_expr; +} + +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:21"><div class="section"><h4 class="noheading">21. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Expression Statement Nodes) <a href="ast.html#1:21">21</a>}</span> +<pre class="prettyprint lang-c"> +struct ast_expression_statement_node { + ast_node_t *expr; +}; + +ast_node_t *ast_create_expression_statement_node(ast_node_t *expr) +{ + ast_node_t *node = ast_create_node(AST_EXPRESSION_STATEMENT, expr-&gt;line, expr-&gt;column, sizeof(struct ast_expression_statement_node)); + struct ast_expression_statement_node *data = ast_get_data(node); + data-&gt;expr = expr; + return node; +} + +ast_node_t *ast_get_expression_statement_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_EXPRESSION_STATEMENT); + struct ast_expression_statement_node *data = ast_get_data(node); + return data-&gt;expr; +} + +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:22"><div class="section"><h4 class="noheading">22. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Label/Case Statement Nodes) <a href="ast.html#1:22">22</a>}</span> +<pre class="prettyprint lang-c"> +struct ast_label_statement_node { + char *label; +}; + +ast_node_t *ast_create_label_statement_node(char *label, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_LABEL_STATEMENT, line, col, sizeof(struct ast_label_statement_node)); + struct ast_label_statement_node *data = ast_get_data(node); + data-&gt;label = label; + return node; +} + +char *ast_get_label_statement_label(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_LABEL_STATEMENT); + struct ast_label_statement_node *data = ast_get_data(node); + return data-&gt;label; +} + +ast_node_t *ast_create_case_statement_node(ast_node_t *expr, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_CASE_STATEMENT, line, col, sizeof(ast_node_t *)); + ast_node_t **data = ast_get_data(node); + *data = expr; + return node; +} + +ast_node_t *ast_get_case_statement_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CASE_STATEMENT); + ast_node_t **data = ast_get_data(node); + return *data; +} + +ast_node_t *ast_create_default_statement_node(int line, int col) +{ + return ast_create_node(AST_DEFAULT_STATEMENT, line, col, 0); +} +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:23"><div class="section"><h4 class="noheading">23. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Compound Statement Nodes) <a href="ast.html#1:23">23</a>}</span> +<pre class="prettyprint lang-c"> +struct ast_compound_statement_node { + ast_node_t **decls_and_stmts; + size_t num_decls_and_stmts; +}; + +ast_node_t *ast_create_compound_statement_node(ast_node_t **decls_and_stmts, size_t num_decls_and_stmts, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_COMPOUND_STATEMENT, line, col, sizeof(struct ast_compound_statement_node)); + struct ast_compound_statement_node *data = ast_get_data(node); + data-&gt;decls_and_stmts = decls_and_stmts; + data-&gt;num_decls_and_stmts = num_decls_and_stmts; + return node; +} + +ast_node_t **ast_get_compound_statement_contents(ast_node_t *node, size_t *num_contents) +{ + assert(ast_get_node_type(node) == AST_COMPOUND_STATEMENT); + struct ast_compound_statement_node *data = ast_get_data(node); + *num_contents = data-&gt;num_decls_and_stmts; + return data-&gt;decls_and_stmts; +} + +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:24"><div class="section"><h4 class="noheading">24. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Conditional Statement Nodes) <a href="ast.html#1:24">24</a>}</span> +<pre class="prettyprint lang-c"> +struct ast_if_statement_node { + ast_node_t *condition; + ast_node_t *true_stmt; + ast_node_t *false_stmt; +}; + +ast_node_t *ast_create_if_statement_node(ast_node_t *condition, ast_node_t *true_stmt, ast_node_t *false_stmt, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_IF_STATEMENT, line, col, sizeof(struct ast_if_statement_node)); + struct ast_if_statement_node *data = ast_get_data(node); + data-&gt;condition = condition; + data-&gt;true_stmt = true_stmt; + data-&gt;false_stmt = false_stmt; + return node; +} + +ast_node_t *ast_get_if_statement_condition(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_IF_STATEMENT); + struct ast_if_statement_node *data = ast_get_data(node); + return data-&gt;condition; +} + +ast_node_t *ast_get_if_statement_true_stmt(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_IF_STATEMENT); + struct ast_if_statement_node *data = ast_get_data(node); + return data-&gt;true_stmt; +} + +ast_node_t *ast_get_if_statement_false_stmt(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_IF_STATEMENT); + struct ast_if_statement_node *data = ast_get_data(node); + return data-&gt;false_stmt; +} + +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:25"><div class="section"><h4 class="noheading">25. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Iteration Statement Nodes) <a href="ast.html#1:25">25</a>}</span> +<pre class="prettyprint lang-c"> + +struct ast_iteration_statement_node { + ast_node_t *condition; + ast_node_t *stmt; +}; + +ast_node_t *ast_create_while_statement_node(ast_node_t *condition, ast_node_t *stmt, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_WHILE_STATEMENT, line, col, sizeof(struct ast_iteration_statement_node)); + struct ast_iteration_statement_node *data = ast_get_data(node); + data-&gt;condition = condition; + data-&gt;stmt = stmt; + return node; +} + +ast_node_t *ast_create_do_while_statement_node(ast_node_t *condition, ast_node_t *stmt, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_DO_WHILE_STATEMENT, line, col, sizeof(struct ast_iteration_statement_node)); + struct ast_iteration_statement_node *data = ast_get_data(node); + data-&gt;condition = condition; + data-&gt;stmt = stmt; + return node; +} + +// Shares the first two members with ast_iteration_statement_node +struct ast_for_statement_node { + ast_node_t *condition; + ast_node_t *stmt; + ast_node_t *init; + ast_node_t *update; + +}; + +ast_node_t *ast_create_for_statement_node(ast_node_t *init, ast_node_t *condition, ast_node_t *update, ast_node_t *stmt, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_FOR_STATEMENT, line, col, sizeof(struct ast_for_statement_node)); + struct ast_for_statement_node *data = ast_get_data(node); + data-&gt;init = init; + data-&gt;condition = condition; + data-&gt;update = update; + data-&gt;stmt = stmt; + return node; +} + +ast_node_t *ast_get_iteration_statement_condition(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_WHILE_STATEMENT || ast_get_node_type(node) == AST_DO_WHILE_STATEMENT || ast_get_node_type(node) == AST_FOR_STATEMENT); + struct ast_iteration_statement_node *data = ast_get_data(node); + return data-&gt;condition; +} + +ast_node_t *ast_get_iteration_statement_stmt(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_WHILE_STATEMENT || ast_get_node_type(node) == AST_DO_WHILE_STATEMENT || ast_get_node_type(node) == AST_FOR_STATEMENT); + struct ast_iteration_statement_node *data = ast_get_data(node); + return data-&gt;stmt; +} + +ast_node_t *ast_get_for_statement_init(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_FOR_STATEMENT); + struct ast_for_statement_node *data = ast_get_data(node); + return data-&gt;init; +} + +ast_node_t *ast_get_for_statement_update(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_FOR_STATEMENT); + struct ast_for_statement_node *data = ast_get_data(node); + return data-&gt;update; +} +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:26"><div class="section"><h4 class="noheading">26. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Jump Statement Nodes) <a href="ast.html#1:26">26</a>}</span> +<pre class="prettyprint lang-c"> +struct ast_goto_statement_node { + char *label; +}; + +ast_node_t *ast_create_goto_statement_node(char *label, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_GOTO_STATEMENT, line, col, sizeof(struct ast_goto_statement_node)); + struct ast_goto_statement_node *data = ast_get_data(node); + data-&gt;label = label; + return node; +} + +char *ast_get_goto_statement_label(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_GOTO_STATEMENT); + struct ast_goto_statement_node *data = ast_get_data(node); + return data-&gt;label; +} + +ast_node_t *ast_create_continue_statement_node(int line, int col) +{ + return ast_create_node(AST_CONTINUE_STATEMENT, line, col, 0); +} + +ast_node_t *ast_create_break_statement_node(int line, int col) +{ + return ast_create_node(AST_BREAK_STATEMENT, line, col, 0); +} + +ast_node_t *ast_create_return_statement_node(ast_node_t *expr, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_RETURN_STATEMENT, line, col, sizeof(ast_node_t *)); + ast_node_t **data = ast_get_data(node); + *data = expr; + return node; +} + +ast_node_t *ast_get_return_statement_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_RETURN_STATEMENT); + ast_node_t **data = ast_get_data(node); + return *data; +} + +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:27"><div class="section"><h4 class="noheading">27. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Switch Statement Nodes) <a href="ast.html#1:27">27</a>}</span> +<pre class="prettyprint lang-c"> + +struct ast_switch_statement_node { + ast_node_t *expr; + ast_node_t *stmt; +}; + +ast_node_t *ast_create_switch_statement_node(ast_node_t *expr, ast_node_t *stmt, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_SWITCH_STATEMENT, line, col, sizeof(struct ast_switch_statement_node)); + struct ast_switch_statement_node *data = ast_get_data(node); + data-&gt;expr = expr; + data-&gt;stmt = stmt; + return node; +} + +ast_node_t *ast_get_switch_statement_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_SWITCH_STATEMENT); + struct ast_switch_statement_node *data = ast_get_data(node); + return data-&gt;expr; +} + +ast_node_t *ast_get_switch_statement_stmt(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_SWITCH_STATEMENT); + struct ast_switch_statement_node *data = ast_get_data(node); + return data-&gt;stmt; +} +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Simple Declaration Nodes) <a href="ast.html#1:27">27</a>}</span> +<pre class="prettyprint lang-c"> +struct var_decl_data { + ast_node_t *type; + char *id; +}; + +ast_node_t *ast_create_var_decl_node(ast_node_t *type, char *id, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_VAR_DECL, line, col, sizeof(struct var_decl_data)); + struct var_decl_data *data = ast_get_data(node); + data-&gt;type = type; + data-&gt;id = id; + return (ast_node_t *)data; +} + +ast_node_t *ast_get_var_decl_type(ast_node_t *node) +{ + struct var_decl_data *data = ast_get_data(node); + return data-&gt;type; +} + +char *ast_get_var_decl_id(ast_node_t *node) +{ + struct var_decl_data *data = ast_get_data(node); + return data-&gt;id; +} + +struct fun_decl_data { + ast_node_t *type; + char *id; + ast_node_t **params; + size_t num_params; +}; + +ast_node_t *ast_create_fun_decl_node(ast_node_t *type, char *id, ast_node_t **params, size_t num_params, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_FUN_DECL, line, col, sizeof(struct fun_decl_data)); + struct fun_decl_data *data = ast_get_data(node); + data-&gt;type = type; + data-&gt;id = id; + data-&gt;params = params; + data-&gt;num_params = num_params; + return (ast_node_t *)data; +} + +ast_node_t *ast_get_fun_decl_type(ast_node_t *node) +{ + struct fun_decl_data *data = ast_get_data(node); + return data-&gt;type; +} + +char *ast_get_fun_decl_id(ast_node_t *node) +{ + struct fun_decl_data *data = ast_get_data(node); + return data-&gt;id; +} + +ast_node_t **ast_get_fun_decl_params(ast_node_t *node, size_t *num_params) +{ + struct fun_decl_data *data = ast_get_data(node); + *num_params = data-&gt;num_params; + return data-&gt;params; +} + +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:28"><div class="section"><h4 class="noheading">28. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Parameter Declaration Nodes) <a href="ast.html#1:28">28</a>}</span> +<pre class="prettyprint lang-c"> +struct param_data { + ast_node_t *type; + char *id; +}; + +ast_node_t *ast_create_param_node(ast_node_t *type, char *id, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_PARAM, line, col, sizeof(struct param_data)); + struct param_data *data = ast_get_data(node); + data-&gt;type = type; + data-&gt;id = id; + return node; +} + +ast_node_t *ast_get_param_type(ast_node_t *node) +{ + struct param_data *data = ast_get_data(node); + return data-&gt;type; +} + +char *ast_get_param_id(ast_node_t *node) +{ + struct param_data *data = ast_get_data(node); + return data-&gt;id; +} + +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:29"><div class="section"><h4 class="noheading">29. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Function Definition Nodes) <a href="ast.html#1:29">29</a>}</span> +<pre class="prettyprint lang-c"> + +struct fun_def_data { + ast_node_t *type; + char *id; + ast_node_t **params; + size_t num_params; + ast_node_t *stmt; +}; + +ast_node_t *ast_create_fun_def_node(ast_node_t *type, char *id, ast_node_t **params, size_t num_params, ast_node_t *stmt, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_FUN_DEF, line, col, sizeof(struct fun_def_data)); + struct fun_def_data *data = ast_get_data(node); + data-&gt;type = type; + data-&gt;id = id; + data-&gt;params = params; + data-&gt;num_params = num_params; + data-&gt;stmt = stmt; + return node; +} + +ast_node_t *ast_get_fun_def_type(ast_node_t *node) +{ + struct fun_def_data *data = ast_get_data(node); + return data-&gt;type; +} + +char *ast_get_fun_def_id(ast_node_t *node) +{ + struct fun_def_data *data = ast_get_data(node); + return data-&gt;id; +} + +ast_node_t **ast_get_fun_def_params(ast_node_t *node, size_t *num_params) +{ + struct fun_def_data *data = ast_get_data(node); + *num_params = data-&gt;num_params; + return data-&gt;params; +} + +ast_node_t *ast_get_fun_def_stmt(ast_node_t *node) +{ + struct fun_def_data *data = ast_get_data(node); + return data-&gt;stmt; +} + +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:30"><div class="section"><h4 class="noheading">30. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Struct Declaration Nodes) <a href="ast.html#1:30">30</a>}</span> +<pre class="prettyprint lang-c"> +struct struct_decl_data { + char *id; + ast_node_t **members; + size_t num_members; +}; + +ast_node_t *ast_create_struct_decl_node(char *id, ast_node_t **members, size_t num_members, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_STRUCT_DECL, line, col, sizeof(struct struct_decl_data)); + struct struct_decl_data *data = ast_get_data(node); + data-&gt;id = id; + data-&gt;members = members; + data-&gt;num_members = num_members; + return node; +} + +char *ast_get_struct_decl_id(ast_node_t *node) +{ + struct struct_decl_data *data = ast_get_data(node); + return data-&gt;id; +} + +ast_node_t **ast_get_struct_decl_members(ast_node_t *node, size_t *num_members) +{ + struct struct_decl_data *data = ast_get_data(node); + *num_members = data-&gt;num_members; + return data-&gt;members; +} +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:31"><div class="section"><h4 class="noheading">31. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Union Declaration Nodes) <a href="ast.html#1:31">31</a>}</span> +<pre class="prettyprint lang-c"> +struct union_decl_data { + char *id; + ast_node_t **members; + size_t num_members; +}; + +ast_node_t *ast_create_union_decl_node(char *id, ast_node_t **members, size_t num_members, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_UNION_DECL, line, col, sizeof(struct union_decl_data)); + struct union_decl_data *data = ast_get_data(node); + data-&gt;id = id; + data-&gt;members = members; + data-&gt;num_members = num_members; + return node; +} + +char *ast_get_union_decl_id(ast_node_t *node) +{ + struct union_decl_data *data = ast_get_data(node); + return data-&gt;id; +} + +ast_node_t **ast_get_union_decl_members(ast_node_t *node, size_t *num_members) +{ + struct union_decl_data *data = ast_get_data(node); + *num_members = data-&gt;num_members; + return data-&gt;members; +} + +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:32"><div class="section"><h4 class="noheading">32. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Enum Declaration Nodes) <a href="ast.html#1:32">32</a>}</span> +<pre class="prettyprint lang-c"> +struct enum_decl_data { + char *id; + ast_node_t **enums; + size_t num_enums; +}; + +ast_node_t *ast_create_enum_decl_node(char *id, ast_node_t **enums, size_t num_enums, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_ENUM_DECL, line, col, sizeof(struct enum_decl_data)); + struct enum_decl_data *data = ast_get_data(node); + data-&gt;id = id; + data-&gt;enums = enums; + data-&gt;num_enums = num_enums; + return node; +} + +char *ast_get_enum_decl_id(ast_node_t *node) +{ + struct enum_decl_data *data = ast_get_data(node); + return data-&gt;id; +} + +ast_node_t **ast_get_enum_decl_enums(ast_node_t *node, size_t *num_enums) +{ + struct enum_decl_data *data = ast_get_data(node); + *num_enums = data-&gt;num_enums; + return data-&gt;enums; +} + +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:33"><div class="section"><h4 class="noheading">33. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Typedef Declaration Nodes) <a href="ast.html#1:33">33</a>}</span> +<pre class="prettyprint lang-c"> +struct typedef_data { + ast_node_t *type; + char *id; +}; + +ast_node_t *ast_create_typedef_node(ast_node_t *type, char *id, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_TYPEDEF, line, col, sizeof(struct typedef_data)); + struct typedef_data *data = ast_get_data(node); + data-&gt;type = type; + data-&gt;id = id; + return node; +} + +ast_node_t *ast_get_typedef_type(ast_node_t *node) +{ + struct typedef_data *data = ast_get_data(node); + return data-&gt;type; +} + +char *ast_get_typedef_id(ast_node_t *node) +{ + struct typedef_data *data = ast_get_data(node); + return data-&gt;id; +} + +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:34"><div class="section"><h4 class="noheading">34. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Types/Members) <a href="ast.html#1:34">34</a>}</span> +<pre class="prettyprint lang-c"> +struct type_data { + token_t **type; + size_t num_type; +}; + +ast_node_t *ast_create_type_node(token_t *type[], size_t num_type, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_TYPE, line, col, sizeof(struct type_data)); + struct type_data *data = ast_get_data(node); + data-&gt;type = type; + data-&gt;num_type = num_type; + return node; +} + +token_t **ast_get_type(ast_node_t *node, size_t *num_type) +{ + struct type_data *data = ast_get_data(node); + *num_type = data-&gt;num_type; + return data-&gt;type; +} + +struct member_data { + ast_node_t *type; + char *id; +}; + +ast_node_t *ast_create_member_node(ast_node_t *type, char *id, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_MEMBER, line, col, sizeof(struct member_data)); + struct member_data *data = ast_get_data(node); + data-&gt;type = type; + data-&gt;id = id; + return node; +} + +ast_node_t *ast_get_member_type(ast_node_t *node) +{ + struct member_data *data = ast_get_data(node); + return data-&gt;type; +} + +char *ast_get_member_id(ast_node_t *node) +{ + struct member_data *data = ast_get_data(node); + return data-&gt;id; +} + +struct enum_member_data { + char *id; + ast_node_t *value; +}; + +ast_node_t *ast_create_enum_member_node(char *id, ast_node_t *value, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_ENUM_MEMBER, line, col, sizeof(struct enum_member_data)); + struct enum_member_data *data = ast_get_data(node); + data-&gt;id = id; + data-&gt;value = value; + return node; +} + +char *ast_get_enum_member_id(ast_node_t *node) +{ + struct enum_member_data *data = ast_get_data(node); + return data-&gt;id; +} + +ast_node_t *ast_get_enum_member_expr(ast_node_t *node) +{ + struct enum_member_data *data = ast_get_data(node); + return data-&gt;value; +} + +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:35"><div class="section"><h4 class="noheading">35. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Translation Unit Nodes) <a href="ast.html#1:35">35</a>}</span> +<pre class="prettyprint lang-c"> +struct translation_unit_data { + ast_node_t **items; + size_t num_items; +}; + +ast_node_t *ast_create_translation_unit_node(ast_node_t **items, size_t num_items, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_TRANSLATION_UNIT, line, col, sizeof(struct translation_unit_data)); + struct translation_unit_data *data = ast_get_data(node); + data-&gt;items = items; + data-&gt;num_items = num_items; + return node; +} + +ast_node_t **ast_get_translation_unit_items(ast_node_t *node, size_t *num_items) +{ + struct translation_unit_data *data = ast_get_data(node); + *num_items = data-&gt;num_items; + return data-&gt;items; +} +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:36"><div class="section"><h4 class="noheading">36. </h4></a> +<p>Freeing the AST is going to be pretty painful. We need to free all the nodes, and all the data associated with them. We'll start by freeing the data associated with each node, and then free the node itself. We'll do this recursively, so that we can free all the nodes in the tree. +</p> + +<div class="codeblock"> +<span class="codeblock_name">{Implementation - Nodes (Freeing) <a href="ast.html#1:36">36</a>}</span> +<pre class="prettyprint lang-c"> +void ast_free_node(ast_node_t *node) { + if (!node) { + return; + } + switch (ast_get_node_type(node)) { + case AST_INTU32: + case AST_INTU64: + case AST_INTS32: + case AST_INTS64: + case AST_FLOAT: + case AST_DOUBLE: + case AST_STRING: + case AST_CHAR: + case AST_VAR: + break; + case AST_SUBSCRIPT: + ast_free_node(ast_get_subscript_expr(node)); + ast_free_node(ast_get_subscript_idx(node)); + free(node); + break; + case AST_DIRECT_COMPONENT_SELECTION: + case AST_INDIRECT_COMPONENT_SELECTION: + ast_free_node(ast_get_component_expr(node)); + free(node); + break; + case AST_FUNCTION_CALL: { + size_t num_args; + ast_node_t **args = ast_get_function_call_args(node, &amp;num_args); + for (size_t i = 0; i &lt; num_args; i++) { + ast_free_node(args[i]); + } + free(args); + ast_free_node(ast_get_function_call_expr(node)); + free(node); + break; + } + case AST_POSTFIX_INC: + case AST_POSTFIX_DEC: { + ast_free_node(ast_get_postfix_expr(node)); + free(node); + break; + } + case AST_UNARY_PLUS: + case AST_UNARY_MINUS: + case AST_LOGICAL_NOT: + case AST_BITWISE_NOT: + case AST_ADDRESS_OF: + case AST_INDIRECTION: + case AST_SIZEOF: + case AST_PRE_INC: + case AST_PRE_DEC: { + ast_free_node(ast_get_unary_expr(node)); + free(node); + break; + } + case AST_CAST: { + ast_free_node(ast_get_cast_type(node)); + ast_free_node(ast_get_cast_expr(node)); + free(node); + break; + } + case AST_MUL: + case AST_DIV: + case AST_MOD: + case AST_ADD: + case AST_SUB: + case AST_LEFT_SHIFT: + case AST_RIGHT_SHIFT: + case AST_LESS_THAN: + case AST_GREATER_THAN: + case AST_LESS_THAN_OR_EQUAL: + case AST_GREATER_THAN_OR_EQUAL: + case AST_EQUAL: + case AST_NOT_EQUAL: + case AST_BITWISE_AND: + case AST_BITWISE_XOR: + case AST_BITWISE_OR: + case AST_LOGICAL_AND: + case AST_LOGICAL_OR: + case AST_COMMA: + case AST_ASSIGN: + case AST_ADD_ASSIGN: + case AST_SUB_ASSIGN: + case AST_MUL_ASSIGN: + case AST_DIV_ASSIGN: + case AST_MOD_ASSIGN: + case AST_LEFT_SHIFT_ASSIGN: + case AST_RIGHT_SHIFT_ASSIGN: + case AST_AND_ASSIGN: + case AST_XOR_ASSIGN: + case AST_OR_ASSIGN: + { + ast_free_node(ast_get_left_expr(node)); + ast_free_node(ast_get_right_expr(node)); + free(node); + break; + } + case AST_CONDITIONAL: { + ast_free_node(ast_get_conditional_condition(node)); + ast_free_node(ast_get_conditional_true_expr(node)); + ast_free_node(ast_get_conditional_false_expr(node)); + free(node); + break; + } + case AST_EXPRESSION_STATEMENT: + ast_free_node(ast_get_expression_statement_expr(node)); + free(node); + break; + case AST_LABEL_STATEMENT: + free(node); + break; + case AST_CASE_STATEMENT: + ast_free_node(ast_get_case_statement_expr(node)); + free(node); + break; + case AST_DEFAULT_STATEMENT: + free(node); + break; + case AST_COMPOUND_STATEMENT: + { + size_t size = 0; + ast_node_t **comp_stmts = ast_get_compound_statement_contents(node, &amp;size); + for(size_t i = 0; i &lt; size; i++) + { + ast_free_node(comp_stmts[i]); + } + free(comp_stmts); + free(node); + break; + } + case AST_IF_STATEMENT: + { + ast_free_node(ast_get_if_statement_condition(node)); + ast_free_node(ast_get_if_statement_true_stmt(node)); + ast_free_node(ast_get_if_statement_false_stmt(node)); + free(node); + break; + } + case AST_WHILE_STATEMENT: + case AST_DO_WHILE_STATEMENT: + { + ast_free_node(ast_get_iteration_statement_condition(node)); + ast_free_node(ast_get_iteration_statement_stmt(node)); + free(node); + break; + } + case AST_FOR_STATEMENT: + { + ast_free_node(ast_get_for_statement_init(node)); + ast_free_node(ast_get_iteration_statement_condition(node)); + ast_free_node(ast_get_for_statement_update(node)); + ast_free_node(ast_get_iteration_statement_stmt(node)); + free(node); + break; + } + case AST_GOTO_STATEMENT: + free(node); + break; + case AST_CONTINUE_STATEMENT: + case AST_BREAK_STATEMENT: + free(node); + break; + case AST_RETURN_STATEMENT: + ast_free_node(ast_get_return_statement_expr(node)); + free(node); + break; + case AST_SWITCH_STATEMENT: + { + ast_free_node(ast_get_switch_statement_expr(node)); + ast_free_node(ast_get_switch_statement_stmt(node)); + free(node); + break; + } + case AST_NULL_STATEMENT: + free(node); + break; + case AST_VAR_DECL: + { + ast_node_t *type = ast_get_var_decl_type(node); + ast_free_node(type); + free(node); + break; + } + case AST_FUN_DECL: + { + ast_node_t *type = ast_get_fun_decl_type(node); + ast_free_node(type); + size_t num_params; + ast_node_t **params = ast_get_fun_decl_params(node, &amp;num_params); + for(size_t i = 0; i &lt; num_params; i++) + { + ast_free_node(params[i]); + } + free(params); + free(node); + break; + } + case AST_PARAM: + { + ast_node_t *type = ast_get_param_type(node); + ast_free_node(type); + free(node); + break; + } + case AST_FUN_DEF: + { + ast_node_t *type = ast_get_fun_def_type(node); + ast_free_node(type); + size_t num_params; + ast_node_t **params = ast_get_fun_def_params(node, &amp;num_params); + for(size_t i = 0; i &lt; num_params; i++) + { + ast_free_node(params[i]); + } + free(params); + ast_free_node(ast_get_fun_def_stmt(node)); + free(node); + break; + } + case AST_STRUCT_DECL: + { + size_t num_members; + ast_node_t **members = ast_get_struct_decl_members(node, &amp;num_members); + for(size_t i = 0; i &lt; num_members; i++) + { + ast_free_node(members[i]); + } + free(members); + free(node); + break; + } + case AST_UNION_DECL: + { + size_t num_members; + ast_node_t **members = ast_get_union_decl_members(node, &amp;num_members); + for(size_t i = 0; i &lt; num_members; i++) + { + ast_free_node(members[i]); + } + free(members); + free(node); + break; + } + case AST_ENUM_DECL: + { + size_t num_enums; + ast_node_t **enums = ast_get_enum_decl_enums(node, &amp;num_enums); + for(size_t i = 0; i &lt; num_enums; i++) + { + ast_free_node(enums[i]); + } + free(enums); + free(node); + break; + } + case AST_TYPEDEF: + { + ast_node_t *type = ast_get_typedef_type(node); + ast_free_node(type); + free(node); + break; + } + case AST_TYPE: + { + token_t **type; + size_t num_type; + type = ast_get_type(node, &amp;num_type); + for(size_t i = 0; i &lt; num_type; i++) + { + free(type[i]); + } + free(type); + free(node); + break; + } + case AST_MEMBER: + { + ast_node_t *type = ast_get_member_type(node); + ast_free_node(type); + free(node); + break; + } + case AST_ENUM_MEMBER: + { + ast_node_t *value = ast_get_enum_member_expr(node); + ast_free_node(value); + free(node); + break; + } + case AST_TRANSLATION_UNIT: + { + size_t num_items; + ast_node_t **items = ast_get_translation_unit_items(node, &amp;num_items); + for(size_t i = 0; i &lt; num_items; i++) + { + ast_free_node(items[i]); + } + free(items); + free(node); + break; + } + default: + assert(0); + } + +} +</pre> + + +<p class="seealso">Used in section <a href="ast.html#1:37">37</a></p> +</div> +</div> +<a name="1:37"><div class="section"><h4 class="noheading">37. </h4></a> + +<div class="codeblock"> +<span class="codeblock_name">{<strong>ast.c</strong> <a href="ast.html#1:37">37</a>}</span> +<pre class="prettyprint lang-c"> +#include &lt;stdlib.h&gt; +#include &lt;assert.h&gt; +#include "ast.h" +<span class="nocode pln">{Implementation - Common Node Structure, <a href="ast.html#1:15">15</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Primary), <a href="ast.html#1:16">16</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Postfix), <a href="ast.html#1:17">17</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Unary/Cast), <a href="ast.html#1:18">18</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Binary/Assign/Comma), <a href="ast.html#1:19">19</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Conditional), <a href="ast.html#1:20">20</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Expression Statement Nodes), <a href="ast.html#1:21">21</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Label/Case Statement Nodes), <a href="ast.html#1:22">22</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Compound Statement Nodes), <a href="ast.html#1:23">23</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Conditional Statement Nodes), <a href="ast.html#1:24">24</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Iteration Statement Nodes), <a href="ast.html#1:25">25</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Jump Statement Nodes), <a href="ast.html#1:26">26</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Switch Statement Nodes), <a href="ast.html#1:27">27</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Simple Declaration Nodes), <a href="ast.html#1:27">27</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Parameter Declaration Nodes), <a href="ast.html#1:28">28</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Function Definition Nodes), <a href="ast.html#1:29">29</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Struct Declaration Nodes), <a href="ast.html#1:30">30</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Union Declaration Nodes), <a href="ast.html#1:31">31</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Enum Declaration Nodes), <a href="ast.html#1:32">32</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Typedef Declaration Nodes), <a href="ast.html#1:33">33</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Types/Members), <a href="ast.html#1:34">34</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Translation Unit Nodes), <a href="ast.html#1:35">35</a>}</span> +<span class="nocode pln">{Implementation - Nodes (Freeing), <a href="ast.html#1:36">36</a>}</span> +</pre> + + + +</div> + +</div> +</body> diff --git a/projects/cminus/code/ast.c b/projects/cminus/code/ast.c @@ -0,0 +1,1422 @@ +/* ast.c */ +#include <stdlib.h> +#include <assert.h> +#include "ast.h" +/* Implementation - Common Node Structure */ +#define AST_MAGIC 0x4153544E4F44ULL // "ASTNOD" + +struct ast_node { + long magic; + int line; + int column; + int hasdata; + short kind; + long opt_data[0]; +}; + +static void* ast_get_data(ast_node_t *node) +{ + assert(node->magic == AST_MAGIC); + assert(node->hasdata); + return node->opt_data; +} + +ast_node_type_t ast_get_node_type(ast_node_t *node) +{ + assert(node->magic == AST_MAGIC); + return node->kind; +} + +int ast_get_node_line(ast_node_t *node) +{ + assert(node->magic == AST_MAGIC); + return node->line; +} + +int ast_get_node_column(ast_node_t *node) +{ + assert(node->magic == AST_MAGIC); + return node->column; +} + +static ast_node_t *ast_create_node(ast_node_type_t kind, int line, int column, size_t data_size) +{ + ast_node_t *node = malloc(sizeof(ast_node_t) + data_size); + node->magic = AST_MAGIC; + node->line = line; + node->column = column; + node->hasdata = data_size > 0; + node->kind = kind; + return node; +} + +/* Implementation - Nodes (Primary) */ +struct ast_int_node { + int64_t value; +}; + +ast_node_t *ast_create_intu32_node(uint32_t value, int line, int column) +{ + ast_node_t *node = + ast_create_node(AST_INTU32, line, column, sizeof(struct ast_int_node)); + struct ast_int_node *data = ast_get_data(node); + data->value = value; + return node; +} + +ast_node_t *ast_create_ints32_node(int32_t value, int line, int column) +{ + ast_node_t *node = + ast_create_node(AST_INTS32, line, column, sizeof(struct ast_int_node)); + struct ast_int_node *data = ast_get_data(node); + data->value = value; + return node; +} + +ast_node_t *ast_create_intu64_node(uint64_t value, int line, int column) +{ + ast_node_t *node = + ast_create_node(AST_INTU64, line, column, sizeof(struct ast_int_node)); + struct ast_int_node *data = ast_get_data(node); + data->value = value; + return node; +} + +ast_node_t *ast_create_ints64_node(int64_t value, int line, int column) +{ + ast_node_t *node = + ast_create_node(AST_INTS64, line, column, sizeof(struct ast_int_node)); + struct ast_int_node *data = ast_get_data(node); + data->value = value; + return node; +} + +int64_t ast_get_int_value(ast_node_t *node) { + assert(ast_get_node_type(node) == AST_INTU32 || ast_get_node_type(node) == AST_INTS32 || ast_get_node_type(node) == AST_INTU64 || ast_get_node_type(node) == AST_INTS64); + struct ast_int_node *data = ast_get_data(node); + return data->value; +} + +struct ast_double_node { + double value; +}; + +struct ast_float_node { + float value; +}; + +ast_node_t *ast_create_float_node(float value, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_FLOAT, line, column, sizeof(struct ast_float_node)); + struct ast_float_node *data = ast_get_data(node); + data->value = value; + return node; +} + +float ast_get_float_value(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_FLOAT); + struct ast_float_node *data = ast_get_data(node); + return data->value; +} + +ast_node_t *ast_create_double_node(double value, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_DOUBLE, line, column, sizeof(struct ast_double_node)); + struct ast_double_node *data = ast_get_data(node); + data->value = value; + return node; +} + +double ast_get_double_value(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_DOUBLE); + struct ast_double_node *data = ast_get_data(node); + return data->value; +} + +struct ast_string_node { + char *value; +}; + +ast_node_t *ast_create_string_node(char *value, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_STRING, line, column, sizeof(struct ast_string_node)); + struct ast_string_node *data = ast_get_data(node); + data->value = value; // We don't duplicate here because the string is in the shared string table + return node; +} + +char *ast_get_string_value(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_STRING); + struct ast_string_node *data = ast_get_data(node); + return data->value; +} + +struct ast_char_node { + char value; +}; + +ast_node_t *ast_create_char_node(char value, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_CHAR, line, column, sizeof(struct ast_char_node)); + struct ast_char_node *data = ast_get_data(node); + data->value = value; + return node; +} + +char ast_get_char_value(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CHAR); + struct ast_char_node *data = ast_get_data(node); + return data->value; +} + +ast_node_t *ast_create_var_node(char *value, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_VAR, line, column, sizeof(struct ast_string_node)); + struct ast_string_node *data = ast_get_data(node); + data->value = value; // We don't duplicate here because the string is in the shared string table + return node; +} + +char *ast_get_var_value(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_VAR); + struct ast_string_node *data = ast_get_data(node); + return data->value; +} + +/* Implementation - Nodes (Postfix) */ +struct ast_subscript_node { + ast_node_t *expr; + ast_node_t *subscript; +}; + +ast_node_t *ast_create_subscript_node(ast_node_t *expr, ast_node_t *subscript, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_SUBSCRIPT, line, column, sizeof(struct ast_subscript_node)); + struct ast_subscript_node *data = ast_get_data(node); + data->expr = expr; + data->subscript = subscript; + return node; +} + +ast_node_t *ast_get_subscript_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_SUBSCRIPT); + struct ast_subscript_node *data = ast_get_data(node); + return data->expr; +} + +ast_node_t *ast_get_subscript_idx(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_SUBSCRIPT); + struct ast_subscript_node *data = ast_get_data(node); + return data->subscript; +} + +struct ast_component_selection_node { + ast_node_t *expr; + char *component; +}; + +ast_node_t *ast_create_direct_component_selection_node(ast_node_t *expr, char *component, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_DIRECT_COMPONENT_SELECTION, line, column, sizeof(struct ast_component_selection_node)); + struct ast_component_selection_node *data = ast_get_data(node); + data->expr = expr; + data->component = component; + return node; +} + +char *ast_get_component(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_DIRECT_COMPONENT_SELECTION); + struct ast_component_selection_node *data = ast_get_data(node); + return data->component; +} + +ast_node_t *ast_get_component_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_DIRECT_COMPONENT_SELECTION); + struct ast_component_selection_node *data = ast_get_data(node); + return data->expr; +} + +ast_node_t *ast_create_indirect_component_selection_node(ast_node_t *expr, char *component, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_INDIRECT_COMPONENT_SELECTION, line, column, sizeof(struct ast_component_selection_node)); + struct ast_component_selection_node *data = ast_get_data(node); + data->expr = expr; + data->component = component; + return node; +} + +struct ast_function_call_node { + ast_node_t *expr; + ast_node_t **args; + size_t num_args; +}; + +ast_node_t *ast_create_function_call_node(ast_node_t *expr, ast_node_t **args, size_t num_args, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_FUNCTION_CALL, line, column, sizeof(struct ast_function_call_node)); + struct ast_function_call_node *data = ast_get_data(node); + data->expr = expr; + data->args = args; + data->num_args = num_args; + return node; +} + +ast_node_t *ast_get_function_call_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_FUNCTION_CALL); + struct ast_function_call_node *data = ast_get_data(node); + return data->expr; +} + +ast_node_t **ast_get_function_call_args(ast_node_t *node, size_t *num_args) +{ + assert(ast_get_node_type(node) == AST_FUNCTION_CALL); + struct ast_function_call_node *data = ast_get_data(node); + *num_args = data->num_args; + return data->args; +} + +ast_node_t *ast_create_postfix_inc_node(ast_node_t *expr, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_POSTFIX_INC, line, column, sizeof(ast_node_t *)); + ast_node_t **data = ast_get_data(node); + *data = expr; + return node; +} + +ast_node_t *ast_create_postfix_dec_node(ast_node_t *expr, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_POSTFIX_DEC, line, column, sizeof(ast_node_t *)); + ast_node_t **data = ast_get_data(node); + *data = expr; + return node; +} + +ast_node_t *ast_get_postfix_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_POSTFIX_INC || ast_get_node_type(node) == AST_POSTFIX_DEC); + ast_node_t **data = ast_get_data(node); + return *data; +} + +/* Implementation - Nodes (Unary/Cast) */ + +#define AST_CREATE_UNARY_NODE(NODE_TYPE, NODE_NAME) \ +ast_node_t *ast_create_##NODE_NAME##_node(ast_node_t *expr, int line, int column) \ +{ \ + ast_node_t *node = ast_create_node(NODE_TYPE, line, column, sizeof(ast_node_t *)); \ + ast_node_t **data = ast_get_data(node); \ + *data = expr; \ + return node; \ +} + +AST_CREATE_UNARY_NODE(AST_UNARY_PLUS, unary_plus) +AST_CREATE_UNARY_NODE(AST_UNARY_MINUS, unary_minus) +AST_CREATE_UNARY_NODE(AST_LOGICAL_NOT, logical_not) +AST_CREATE_UNARY_NODE(AST_BITWISE_NOT, bitwise_not) +AST_CREATE_UNARY_NODE(AST_ADDRESS_OF, address_of) +AST_CREATE_UNARY_NODE(AST_INDIRECTION, indirection) +AST_CREATE_UNARY_NODE(AST_SIZEOF, sizeof) +AST_CREATE_UNARY_NODE(AST_PRE_INC, pre_inc) +AST_CREATE_UNARY_NODE(AST_PRE_DEC, pre_dec) + +ast_node_t *ast_create_cast_node(ast_node_t *type, ast_node_t *expr, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_CAST, line, column, 2 * sizeof(ast_node_t *)); + ast_node_t **data = ast_get_data(node); + data[0] = type; + data[1] = expr; + return node; +} + +ast_node_t *ast_get_unary_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_UNARY_PLUS || ast_get_node_type(node) == AST_UNARY_MINUS || ast_get_node_type(node) == AST_LOGICAL_NOT || ast_get_node_type(node) == AST_BITWISE_NOT || ast_get_node_type(node) == AST_ADDRESS_OF || ast_get_node_type(node) == AST_INDIRECTION || ast_get_node_type(node) == AST_SIZEOF || ast_get_node_type(node) == AST_PRE_INC || ast_get_node_type(node) == AST_PRE_DEC || ast_get_node_type(node) == AST_CAST); + ast_node_t **data = ast_get_data(node); + return data[0]; +} + +ast_node_t *ast_get_cast_type(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CAST); + ast_node_t **data = ast_get_data(node); + return data[0]; +} + +ast_node_t *ast_get_cast_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CAST); + ast_node_t **data = ast_get_data(node); + return data[1]; +} + + +/* Implementation - Nodes (Binary/Assign/Comma) */ +struct ast_binary_node { + ast_node_t *left; + ast_node_t *right; +}; + +// Macro to generate binary AST node creation functions +#define AST_CREATE_BINARY_NODE(NODE_TYPE, NODE_NAME) \ +ast_node_t *ast_create_##NODE_NAME##_node(ast_node_t *left, ast_node_t *right, int line, int column) \ +{ \ + ast_node_t *node = ast_create_node(NODE_TYPE, line, column, sizeof(struct ast_binary_node)); \ + struct ast_binary_node *data = ast_get_data(node); \ + data->left = left; \ + data->right = right; \ + return node; \ +} + +AST_CREATE_BINARY_NODE(AST_MUL, mul) +AST_CREATE_BINARY_NODE(AST_DIV, div) +AST_CREATE_BINARY_NODE(AST_MOD, mod) +AST_CREATE_BINARY_NODE(AST_ADD, add) +AST_CREATE_BINARY_NODE(AST_SUB, sub) +AST_CREATE_BINARY_NODE(AST_LEFT_SHIFT, left_shift) +AST_CREATE_BINARY_NODE(AST_RIGHT_SHIFT, right_shift) +AST_CREATE_BINARY_NODE(AST_LESS_THAN, less_than) +AST_CREATE_BINARY_NODE(AST_GREATER_THAN, greater_than) +AST_CREATE_BINARY_NODE(AST_LESS_THAN_OR_EQUAL, less_than_or_equal) +AST_CREATE_BINARY_NODE(AST_GREATER_THAN_OR_EQUAL, greater_than_or_equal) +AST_CREATE_BINARY_NODE(AST_EQUAL, equal) +AST_CREATE_BINARY_NODE(AST_NOT_EQUAL, not_equal) +AST_CREATE_BINARY_NODE(AST_BITWISE_AND, bitwise_and) +AST_CREATE_BINARY_NODE(AST_BITWISE_XOR, bitwise_xor) +AST_CREATE_BINARY_NODE(AST_BITWISE_OR, bitwise_or) +AST_CREATE_BINARY_NODE(AST_LOGICAL_AND, logical_and) +AST_CREATE_BINARY_NODE(AST_LOGICAL_OR, logical_or) +AST_CREATE_BINARY_NODE(AST_ASSIGN, assign) +AST_CREATE_BINARY_NODE(AST_ADD_ASSIGN, add_assign) +AST_CREATE_BINARY_NODE(AST_SUB_ASSIGN, sub_assign) +AST_CREATE_BINARY_NODE(AST_MUL_ASSIGN, mul_assign) +AST_CREATE_BINARY_NODE(AST_DIV_ASSIGN, div_assign) +AST_CREATE_BINARY_NODE(AST_MOD_ASSIGN, mod_assign) +AST_CREATE_BINARY_NODE(AST_LEFT_SHIFT_ASSIGN, left_shift_assign) +AST_CREATE_BINARY_NODE(AST_RIGHT_SHIFT_ASSIGN, right_shift_assign) +AST_CREATE_BINARY_NODE(AST_AND_ASSIGN, bitwise_and_assign) +AST_CREATE_BINARY_NODE(AST_XOR_ASSIGN, bitwise_xor_assign) +AST_CREATE_BINARY_NODE(AST_OR_ASSIGN, bitwise_or_assign) +AST_CREATE_BINARY_NODE(AST_COMMA, comma) + +ast_node_t *ast_get_left_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_MUL || ast_get_node_type(node) == AST_DIV || ast_get_node_type(node) == AST_MOD + || ast_get_node_type(node) == AST_ADD || ast_get_node_type(node) == AST_SUB || ast_get_node_type(node) == AST_LEFT_SHIFT + || ast_get_node_type(node) == AST_RIGHT_SHIFT || ast_get_node_type(node) == AST_LESS_THAN || ast_get_node_type(node) == AST_GREATER_THAN + || ast_get_node_type(node) == AST_LESS_THAN_OR_EQUAL || ast_get_node_type(node) == AST_GREATER_THAN_OR_EQUAL + || ast_get_node_type(node) == AST_EQUAL || ast_get_node_type(node) == AST_NOT_EQUAL + || ast_get_node_type(node) == AST_BITWISE_AND || ast_get_node_type(node) == AST_BITWISE_XOR || ast_get_node_type(node) == AST_BITWISE_OR + || ast_get_node_type(node) == AST_LOGICAL_AND || ast_get_node_type(node) == AST_LOGICAL_OR || ast_get_node_type(node) == AST_ASSIGN + || ast_get_node_type(node) == AST_ADD_ASSIGN || ast_get_node_type(node) == AST_SUB_ASSIGN || ast_get_node_type(node) == AST_MUL_ASSIGN || ast_get_node_type(node) == AST_DIV_ASSIGN + || ast_get_node_type(node) == AST_MOD_ASSIGN || ast_get_node_type(node) == AST_LEFT_SHIFT_ASSIGN || ast_get_node_type(node) == AST_RIGHT_SHIFT_ASSIGN || ast_get_node_type(node) == AST_AND_ASSIGN + || ast_get_node_type(node) == AST_XOR_ASSIGN || ast_get_node_type(node) == AST_OR_ASSIGN || ast_get_node_type(node) == AST_COMMA); + struct ast_binary_node *data = ast_get_data(node); + return data->left; +} + +ast_node_t *ast_get_right_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_MUL || ast_get_node_type(node) == AST_DIV || ast_get_node_type(node) == AST_MOD + || ast_get_node_type(node) == AST_ADD || ast_get_node_type(node) == AST_SUB || ast_get_node_type(node) == AST_LEFT_SHIFT + || ast_get_node_type(node) == AST_RIGHT_SHIFT || ast_get_node_type(node) == AST_LESS_THAN || ast_get_node_type(node) == AST_GREATER_THAN + || ast_get_node_type(node) == AST_LESS_THAN_OR_EQUAL || ast_get_node_type(node) == AST_GREATER_THAN_OR_EQUAL + || ast_get_node_type(node) == AST_EQUAL || ast_get_node_type(node) == AST_NOT_EQUAL + || ast_get_node_type(node) == AST_BITWISE_AND || ast_get_node_type(node) == AST_BITWISE_XOR || ast_get_node_type(node) == AST_BITWISE_OR + || ast_get_node_type(node) == AST_LOGICAL_AND || ast_get_node_type(node) == AST_LOGICAL_OR || ast_get_node_type(node) == AST_ASSIGN + || ast_get_node_type(node) == AST_ADD_ASSIGN || ast_get_node_type(node) == AST_SUB_ASSIGN || ast_get_node_type(node) == AST_MUL_ASSIGN || ast_get_node_type(node) == AST_DIV_ASSIGN + || ast_get_node_type(node) == AST_MOD_ASSIGN || ast_get_node_type(node) == AST_LEFT_SHIFT_ASSIGN || ast_get_node_type(node) == AST_RIGHT_SHIFT_ASSIGN || ast_get_node_type(node) == AST_AND_ASSIGN + || ast_get_node_type(node) == AST_XOR_ASSIGN || ast_get_node_type(node) == AST_OR_ASSIGN || ast_get_node_type(node) == AST_COMMA); + struct ast_binary_node *data = ast_get_data(node); + return data->right; +} + + +/* Implementation - Nodes (Conditional) */ +struct ast_conditional_node { + ast_node_t *condition; + ast_node_t *true_expr; + ast_node_t *false_expr; +}; + +ast_node_t *ast_create_conditional_node(ast_node_t *condition, ast_node_t *true_expr, ast_node_t *false_expr, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_CONDITIONAL, line, column, sizeof(struct ast_conditional_node)); + struct ast_conditional_node *data = ast_get_data(node); + data->condition = condition; + data->true_expr = true_expr; + data->false_expr = false_expr; + return node; +} + +ast_node_t *ast_get_conditional_condition(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CONDITIONAL); + struct ast_conditional_node *data = ast_get_data(node); + return data->condition; +} + +ast_node_t *ast_get_conditional_true_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CONDITIONAL); + struct ast_conditional_node *data = ast_get_data(node); + return data->true_expr; +} + +ast_node_t *ast_get_conditional_false_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CONDITIONAL); + struct ast_conditional_node *data = ast_get_data(node); + return data->false_expr; +} + + +/* Implementation - Nodes (Expression Statement Nodes) */ +struct ast_expression_statement_node { + ast_node_t *expr; +}; + +ast_node_t *ast_create_expression_statement_node(ast_node_t *expr) +{ + ast_node_t *node = ast_create_node(AST_EXPRESSION_STATEMENT, expr->line, expr->column, sizeof(struct ast_expression_statement_node)); + struct ast_expression_statement_node *data = ast_get_data(node); + data->expr = expr; + return node; +} + +ast_node_t *ast_get_expression_statement_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_EXPRESSION_STATEMENT); + struct ast_expression_statement_node *data = ast_get_data(node); + return data->expr; +} + + +/* Implementation - Nodes (Label/Case Statement Nodes) */ +struct ast_label_statement_node { + char *label; +}; + +ast_node_t *ast_create_label_statement_node(char *label, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_LABEL_STATEMENT, line, col, sizeof(struct ast_label_statement_node)); + struct ast_label_statement_node *data = ast_get_data(node); + data->label = label; + return node; +} + +char *ast_get_label_statement_label(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_LABEL_STATEMENT); + struct ast_label_statement_node *data = ast_get_data(node); + return data->label; +} + +ast_node_t *ast_create_case_statement_node(ast_node_t *expr, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_CASE_STATEMENT, line, col, sizeof(ast_node_t *)); + ast_node_t **data = ast_get_data(node); + *data = expr; + return node; +} + +ast_node_t *ast_get_case_statement_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CASE_STATEMENT); + ast_node_t **data = ast_get_data(node); + return *data; +} + +ast_node_t *ast_create_default_statement_node(int line, int col) +{ + return ast_create_node(AST_DEFAULT_STATEMENT, line, col, 0); +} + +/* Implementation - Nodes (Compound Statement Nodes) */ +struct ast_compound_statement_node { + ast_node_t **decls_and_stmts; + size_t num_decls_and_stmts; +}; + +ast_node_t *ast_create_compound_statement_node(ast_node_t **decls_and_stmts, size_t num_decls_and_stmts, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_COMPOUND_STATEMENT, line, col, sizeof(struct ast_compound_statement_node)); + struct ast_compound_statement_node *data = ast_get_data(node); + data->decls_and_stmts = decls_and_stmts; + data->num_decls_and_stmts = num_decls_and_stmts; + return node; +} + +ast_node_t **ast_get_compound_statement_contents(ast_node_t *node, size_t *num_contents) +{ + assert(ast_get_node_type(node) == AST_COMPOUND_STATEMENT); + struct ast_compound_statement_node *data = ast_get_data(node); + *num_contents = data->num_decls_and_stmts; + return data->decls_and_stmts; +} + + +/* Implementation - Nodes (Conditional Statement Nodes) */ +struct ast_if_statement_node { + ast_node_t *condition; + ast_node_t *true_stmt; + ast_node_t *false_stmt; +}; + +ast_node_t *ast_create_if_statement_node(ast_node_t *condition, ast_node_t *true_stmt, ast_node_t *false_stmt, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_IF_STATEMENT, line, col, sizeof(struct ast_if_statement_node)); + struct ast_if_statement_node *data = ast_get_data(node); + data->condition = condition; + data->true_stmt = true_stmt; + data->false_stmt = false_stmt; + return node; +} + +ast_node_t *ast_get_if_statement_condition(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_IF_STATEMENT); + struct ast_if_statement_node *data = ast_get_data(node); + return data->condition; +} + +ast_node_t *ast_get_if_statement_true_stmt(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_IF_STATEMENT); + struct ast_if_statement_node *data = ast_get_data(node); + return data->true_stmt; +} + +ast_node_t *ast_get_if_statement_false_stmt(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_IF_STATEMENT); + struct ast_if_statement_node *data = ast_get_data(node); + return data->false_stmt; +} + + +/* Implementation - Nodes (Iteration Statement Nodes) */ + +struct ast_iteration_statement_node { + ast_node_t *condition; + ast_node_t *stmt; +}; + +ast_node_t *ast_create_while_statement_node(ast_node_t *condition, ast_node_t *stmt, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_WHILE_STATEMENT, line, col, sizeof(struct ast_iteration_statement_node)); + struct ast_iteration_statement_node *data = ast_get_data(node); + data->condition = condition; + data->stmt = stmt; + return node; +} + +ast_node_t *ast_create_do_while_statement_node(ast_node_t *condition, ast_node_t *stmt, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_DO_WHILE_STATEMENT, line, col, sizeof(struct ast_iteration_statement_node)); + struct ast_iteration_statement_node *data = ast_get_data(node); + data->condition = condition; + data->stmt = stmt; + return node; +} + +// Shares the first two members with ast_iteration_statement_node +struct ast_for_statement_node { + ast_node_t *condition; + ast_node_t *stmt; + ast_node_t *init; + ast_node_t *update; + +}; + +ast_node_t *ast_create_for_statement_node(ast_node_t *init, ast_node_t *condition, ast_node_t *update, ast_node_t *stmt, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_FOR_STATEMENT, line, col, sizeof(struct ast_for_statement_node)); + struct ast_for_statement_node *data = ast_get_data(node); + data->init = init; + data->condition = condition; + data->update = update; + data->stmt = stmt; + return node; +} + +ast_node_t *ast_get_iteration_statement_condition(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_WHILE_STATEMENT || ast_get_node_type(node) == AST_DO_WHILE_STATEMENT || ast_get_node_type(node) == AST_FOR_STATEMENT); + struct ast_iteration_statement_node *data = ast_get_data(node); + return data->condition; +} + +ast_node_t *ast_get_iteration_statement_stmt(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_WHILE_STATEMENT || ast_get_node_type(node) == AST_DO_WHILE_STATEMENT || ast_get_node_type(node) == AST_FOR_STATEMENT); + struct ast_iteration_statement_node *data = ast_get_data(node); + return data->stmt; +} + +ast_node_t *ast_get_for_statement_init(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_FOR_STATEMENT); + struct ast_for_statement_node *data = ast_get_data(node); + return data->init; +} + +ast_node_t *ast_get_for_statement_update(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_FOR_STATEMENT); + struct ast_for_statement_node *data = ast_get_data(node); + return data->update; +} + +/* Implementation - Nodes (Jump Statement Nodes) */ +struct ast_goto_statement_node { + char *label; +}; + +ast_node_t *ast_create_goto_statement_node(char *label, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_GOTO_STATEMENT, line, col, sizeof(struct ast_goto_statement_node)); + struct ast_goto_statement_node *data = ast_get_data(node); + data->label = label; + return node; +} + +char *ast_get_goto_statement_label(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_GOTO_STATEMENT); + struct ast_goto_statement_node *data = ast_get_data(node); + return data->label; +} + +ast_node_t *ast_create_continue_statement_node(int line, int col) +{ + return ast_create_node(AST_CONTINUE_STATEMENT, line, col, 0); +} + +ast_node_t *ast_create_break_statement_node(int line, int col) +{ + return ast_create_node(AST_BREAK_STATEMENT, line, col, 0); +} + +ast_node_t *ast_create_return_statement_node(ast_node_t *expr, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_RETURN_STATEMENT, line, col, sizeof(ast_node_t *)); + ast_node_t **data = ast_get_data(node); + *data = expr; + return node; +} + +ast_node_t *ast_get_return_statement_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_RETURN_STATEMENT); + ast_node_t **data = ast_get_data(node); + return *data; +} + + +/* Implementation - Nodes (Switch Statement Nodes) */ + +struct ast_switch_statement_node { + ast_node_t *expr; + ast_node_t *stmt; +}; + +ast_node_t *ast_create_switch_statement_node(ast_node_t *expr, ast_node_t *stmt, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_SWITCH_STATEMENT, line, col, sizeof(struct ast_switch_statement_node)); + struct ast_switch_statement_node *data = ast_get_data(node); + data->expr = expr; + data->stmt = stmt; + return node; +} + +ast_node_t *ast_get_switch_statement_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_SWITCH_STATEMENT); + struct ast_switch_statement_node *data = ast_get_data(node); + return data->expr; +} + +ast_node_t *ast_get_switch_statement_stmt(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_SWITCH_STATEMENT); + struct ast_switch_statement_node *data = ast_get_data(node); + return data->stmt; +} + +/* Implementation - Nodes (Simple Declaration Nodes) */ +struct var_decl_data { + ast_node_t *type; + char *id; +}; + +ast_node_t *ast_create_var_decl_node(ast_node_t *type, char *id, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_VAR_DECL, line, col, sizeof(struct var_decl_data)); + struct var_decl_data *data = ast_get_data(node); + data->type = type; + data->id = id; + return (ast_node_t *)data; +} + +ast_node_t *ast_get_var_decl_type(ast_node_t *node) +{ + struct var_decl_data *data = ast_get_data(node); + return data->type; +} + +char *ast_get_var_decl_id(ast_node_t *node) +{ + struct var_decl_data *data = ast_get_data(node); + return data->id; +} + +struct fun_decl_data { + ast_node_t *type; + char *id; + ast_node_t **params; + size_t num_params; +}; + +ast_node_t *ast_create_fun_decl_node(ast_node_t *type, char *id, ast_node_t **params, size_t num_params, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_FUN_DECL, line, col, sizeof(struct fun_decl_data)); + struct fun_decl_data *data = ast_get_data(node); + data->type = type; + data->id = id; + data->params = params; + data->num_params = num_params; + return (ast_node_t *)data; +} + +ast_node_t *ast_get_fun_decl_type(ast_node_t *node) +{ + struct fun_decl_data *data = ast_get_data(node); + return data->type; +} + +char *ast_get_fun_decl_id(ast_node_t *node) +{ + struct fun_decl_data *data = ast_get_data(node); + return data->id; +} + +ast_node_t **ast_get_fun_decl_params(ast_node_t *node, size_t *num_params) +{ + struct fun_decl_data *data = ast_get_data(node); + *num_params = data->num_params; + return data->params; +} + + +/* Implementation - Nodes (Parameter Declaration Nodes) */ +struct param_data { + ast_node_t *type; + char *id; +}; + +ast_node_t *ast_create_param_node(ast_node_t *type, char *id, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_PARAM, line, col, sizeof(struct param_data)); + struct param_data *data = ast_get_data(node); + data->type = type; + data->id = id; + return node; +} + +ast_node_t *ast_get_param_type(ast_node_t *node) +{ + struct param_data *data = ast_get_data(node); + return data->type; +} + +char *ast_get_param_id(ast_node_t *node) +{ + struct param_data *data = ast_get_data(node); + return data->id; +} + + +/* Implementation - Nodes (Function Definition Nodes) */ + +struct fun_def_data { + ast_node_t *type; + char *id; + ast_node_t **params; + size_t num_params; + ast_node_t *stmt; +}; + +ast_node_t *ast_create_fun_def_node(ast_node_t *type, char *id, ast_node_t **params, size_t num_params, ast_node_t *stmt, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_FUN_DEF, line, col, sizeof(struct fun_def_data)); + struct fun_def_data *data = ast_get_data(node); + data->type = type; + data->id = id; + data->params = params; + data->num_params = num_params; + data->stmt = stmt; + return node; +} + +ast_node_t *ast_get_fun_def_type(ast_node_t *node) +{ + struct fun_def_data *data = ast_get_data(node); + return data->type; +} + +char *ast_get_fun_def_id(ast_node_t *node) +{ + struct fun_def_data *data = ast_get_data(node); + return data->id; +} + +ast_node_t **ast_get_fun_def_params(ast_node_t *node, size_t *num_params) +{ + struct fun_def_data *data = ast_get_data(node); + *num_params = data->num_params; + return data->params; +} + +ast_node_t *ast_get_fun_def_stmt(ast_node_t *node) +{ + struct fun_def_data *data = ast_get_data(node); + return data->stmt; +} + + +/* Implementation - Nodes (Struct Declaration Nodes) */ +struct struct_decl_data { + char *id; + ast_node_t **members; + size_t num_members; +}; + +ast_node_t *ast_create_struct_decl_node(char *id, ast_node_t **members, size_t num_members, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_STRUCT_DECL, line, col, sizeof(struct struct_decl_data)); + struct struct_decl_data *data = ast_get_data(node); + data->id = id; + data->members = members; + data->num_members = num_members; + return node; +} + +char *ast_get_struct_decl_id(ast_node_t *node) +{ + struct struct_decl_data *data = ast_get_data(node); + return data->id; +} + +ast_node_t **ast_get_struct_decl_members(ast_node_t *node, size_t *num_members) +{ + struct struct_decl_data *data = ast_get_data(node); + *num_members = data->num_members; + return data->members; +} + +/* Implementation - Nodes (Union Declaration Nodes) */ +struct union_decl_data { + char *id; + ast_node_t **members; + size_t num_members; +}; + +ast_node_t *ast_create_union_decl_node(char *id, ast_node_t **members, size_t num_members, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_UNION_DECL, line, col, sizeof(struct union_decl_data)); + struct union_decl_data *data = ast_get_data(node); + data->id = id; + data->members = members; + data->num_members = num_members; + return node; +} + +char *ast_get_union_decl_id(ast_node_t *node) +{ + struct union_decl_data *data = ast_get_data(node); + return data->id; +} + +ast_node_t **ast_get_union_decl_members(ast_node_t *node, size_t *num_members) +{ + struct union_decl_data *data = ast_get_data(node); + *num_members = data->num_members; + return data->members; +} + + +/* Implementation - Nodes (Enum Declaration Nodes) */ +struct enum_decl_data { + char *id; + ast_node_t **enums; + size_t num_enums; +}; + +ast_node_t *ast_create_enum_decl_node(char *id, ast_node_t **enums, size_t num_enums, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_ENUM_DECL, line, col, sizeof(struct enum_decl_data)); + struct enum_decl_data *data = ast_get_data(node); + data->id = id; + data->enums = enums; + data->num_enums = num_enums; + return node; +} + +char *ast_get_enum_decl_id(ast_node_t *node) +{ + struct enum_decl_data *data = ast_get_data(node); + return data->id; +} + +ast_node_t **ast_get_enum_decl_enums(ast_node_t *node, size_t *num_enums) +{ + struct enum_decl_data *data = ast_get_data(node); + *num_enums = data->num_enums; + return data->enums; +} + + +/* Implementation - Nodes (Typedef Declaration Nodes) */ +struct typedef_data { + ast_node_t *type; + char *id; +}; + +ast_node_t *ast_create_typedef_node(ast_node_t *type, char *id, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_TYPEDEF, line, col, sizeof(struct typedef_data)); + struct typedef_data *data = ast_get_data(node); + data->type = type; + data->id = id; + return node; +} + +ast_node_t *ast_get_typedef_type(ast_node_t *node) +{ + struct typedef_data *data = ast_get_data(node); + return data->type; +} + +char *ast_get_typedef_id(ast_node_t *node) +{ + struct typedef_data *data = ast_get_data(node); + return data->id; +} + + +/* Implementation - Nodes (Types/Members) */ +struct type_data { + token_t **type; + size_t num_type; +}; + +ast_node_t *ast_create_type_node(token_t *type[], size_t num_type, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_TYPE, line, col, sizeof(struct type_data)); + struct type_data *data = ast_get_data(node); + data->type = type; + data->num_type = num_type; + return node; +} + +token_t **ast_get_type(ast_node_t *node, size_t *num_type) +{ + struct type_data *data = ast_get_data(node); + *num_type = data->num_type; + return data->type; +} + +struct member_data { + ast_node_t *type; + char *id; +}; + +ast_node_t *ast_create_member_node(ast_node_t *type, char *id, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_MEMBER, line, col, sizeof(struct member_data)); + struct member_data *data = ast_get_data(node); + data->type = type; + data->id = id; + return node; +} + +ast_node_t *ast_get_member_type(ast_node_t *node) +{ + struct member_data *data = ast_get_data(node); + return data->type; +} + +char *ast_get_member_id(ast_node_t *node) +{ + struct member_data *data = ast_get_data(node); + return data->id; +} + +struct enum_member_data { + char *id; + ast_node_t *value; +}; + +ast_node_t *ast_create_enum_member_node(char *id, ast_node_t *value, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_ENUM_MEMBER, line, col, sizeof(struct enum_member_data)); + struct enum_member_data *data = ast_get_data(node); + data->id = id; + data->value = value; + return node; +} + +char *ast_get_enum_member_id(ast_node_t *node) +{ + struct enum_member_data *data = ast_get_data(node); + return data->id; +} + +ast_node_t *ast_get_enum_member_expr(ast_node_t *node) +{ + struct enum_member_data *data = ast_get_data(node); + return data->value; +} + + +/* Implementation - Nodes (Translation Unit Nodes) */ +struct translation_unit_data { + ast_node_t **items; + size_t num_items; +}; + +ast_node_t *ast_create_translation_unit_node(ast_node_t **items, size_t num_items, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_TRANSLATION_UNIT, line, col, sizeof(struct translation_unit_data)); + struct translation_unit_data *data = ast_get_data(node); + data->items = items; + data->num_items = num_items; + return node; +} + +ast_node_t **ast_get_translation_unit_items(ast_node_t *node, size_t *num_items) +{ + struct translation_unit_data *data = ast_get_data(node); + *num_items = data->num_items; + return data->items; +} + +/* Implementation - Nodes (Freeing) */ +void ast_free_node(ast_node_t *node) { + if (!node) { + return; + } + switch (ast_get_node_type(node)) { + case AST_INTU32: + case AST_INTU64: + case AST_INTS32: + case AST_INTS64: + case AST_FLOAT: + case AST_DOUBLE: + case AST_STRING: + case AST_CHAR: + case AST_VAR: + break; + case AST_SUBSCRIPT: + ast_free_node(ast_get_subscript_expr(node)); + ast_free_node(ast_get_subscript_idx(node)); + free(node); + break; + case AST_DIRECT_COMPONENT_SELECTION: + case AST_INDIRECT_COMPONENT_SELECTION: + ast_free_node(ast_get_component_expr(node)); + free(node); + break; + case AST_FUNCTION_CALL: { + size_t num_args; + ast_node_t **args = ast_get_function_call_args(node, &num_args); + for (size_t i = 0; i < num_args; i++) { + ast_free_node(args[i]); + } + free(args); + ast_free_node(ast_get_function_call_expr(node)); + free(node); + break; + } + case AST_POSTFIX_INC: + case AST_POSTFIX_DEC: { + ast_free_node(ast_get_postfix_expr(node)); + free(node); + break; + } + case AST_UNARY_PLUS: + case AST_UNARY_MINUS: + case AST_LOGICAL_NOT: + case AST_BITWISE_NOT: + case AST_ADDRESS_OF: + case AST_INDIRECTION: + case AST_SIZEOF: + case AST_PRE_INC: + case AST_PRE_DEC: { + ast_free_node(ast_get_unary_expr(node)); + free(node); + break; + } + case AST_CAST: { + ast_free_node(ast_get_cast_type(node)); + ast_free_node(ast_get_cast_expr(node)); + free(node); + break; + } + case AST_MUL: + case AST_DIV: + case AST_MOD: + case AST_ADD: + case AST_SUB: + case AST_LEFT_SHIFT: + case AST_RIGHT_SHIFT: + case AST_LESS_THAN: + case AST_GREATER_THAN: + case AST_LESS_THAN_OR_EQUAL: + case AST_GREATER_THAN_OR_EQUAL: + case AST_EQUAL: + case AST_NOT_EQUAL: + case AST_BITWISE_AND: + case AST_BITWISE_XOR: + case AST_BITWISE_OR: + case AST_LOGICAL_AND: + case AST_LOGICAL_OR: + case AST_COMMA: + case AST_ASSIGN: + case AST_ADD_ASSIGN: + case AST_SUB_ASSIGN: + case AST_MUL_ASSIGN: + case AST_DIV_ASSIGN: + case AST_MOD_ASSIGN: + case AST_LEFT_SHIFT_ASSIGN: + case AST_RIGHT_SHIFT_ASSIGN: + case AST_AND_ASSIGN: + case AST_XOR_ASSIGN: + case AST_OR_ASSIGN: + { + ast_free_node(ast_get_left_expr(node)); + ast_free_node(ast_get_right_expr(node)); + free(node); + break; + } + case AST_CONDITIONAL: { + ast_free_node(ast_get_conditional_condition(node)); + ast_free_node(ast_get_conditional_true_expr(node)); + ast_free_node(ast_get_conditional_false_expr(node)); + free(node); + break; + } + case AST_EXPRESSION_STATEMENT: + ast_free_node(ast_get_expression_statement_expr(node)); + free(node); + break; + case AST_LABEL_STATEMENT: + free(node); + break; + case AST_CASE_STATEMENT: + ast_free_node(ast_get_case_statement_expr(node)); + free(node); + break; + case AST_DEFAULT_STATEMENT: + free(node); + break; + case AST_COMPOUND_STATEMENT: + { + size_t size = 0; + ast_node_t **comp_stmts = ast_get_compound_statement_contents(node, &size); + for(size_t i = 0; i < size; i++) + { + ast_free_node(comp_stmts[i]); + } + free(comp_stmts); + free(node); + break; + } + case AST_IF_STATEMENT: + { + ast_free_node(ast_get_if_statement_condition(node)); + ast_free_node(ast_get_if_statement_true_stmt(node)); + ast_free_node(ast_get_if_statement_false_stmt(node)); + free(node); + break; + } + case AST_WHILE_STATEMENT: + case AST_DO_WHILE_STATEMENT: + { + ast_free_node(ast_get_iteration_statement_condition(node)); + ast_free_node(ast_get_iteration_statement_stmt(node)); + free(node); + break; + } + case AST_FOR_STATEMENT: + { + ast_free_node(ast_get_for_statement_init(node)); + ast_free_node(ast_get_iteration_statement_condition(node)); + ast_free_node(ast_get_for_statement_update(node)); + ast_free_node(ast_get_iteration_statement_stmt(node)); + free(node); + break; + } + case AST_GOTO_STATEMENT: + free(node); + break; + case AST_CONTINUE_STATEMENT: + case AST_BREAK_STATEMENT: + free(node); + break; + case AST_RETURN_STATEMENT: + ast_free_node(ast_get_return_statement_expr(node)); + free(node); + break; + case AST_SWITCH_STATEMENT: + { + ast_free_node(ast_get_switch_statement_expr(node)); + ast_free_node(ast_get_switch_statement_stmt(node)); + free(node); + break; + } + case AST_NULL_STATEMENT: + free(node); + break; + case AST_VAR_DECL: + { + ast_node_t *type = ast_get_var_decl_type(node); + ast_free_node(type); + free(node); + break; + } + case AST_FUN_DECL: + { + ast_node_t *type = ast_get_fun_decl_type(node); + ast_free_node(type); + size_t num_params; + ast_node_t **params = ast_get_fun_decl_params(node, &num_params); + for(size_t i = 0; i < num_params; i++) + { + ast_free_node(params[i]); + } + free(params); + free(node); + break; + } + case AST_PARAM: + { + ast_node_t *type = ast_get_param_type(node); + ast_free_node(type); + free(node); + break; + } + case AST_FUN_DEF: + { + ast_node_t *type = ast_get_fun_def_type(node); + ast_free_node(type); + size_t num_params; + ast_node_t **params = ast_get_fun_def_params(node, &num_params); + for(size_t i = 0; i < num_params; i++) + { + ast_free_node(params[i]); + } + free(params); + ast_free_node(ast_get_fun_def_stmt(node)); + free(node); + break; + } + case AST_STRUCT_DECL: + { + size_t num_members; + ast_node_t **members = ast_get_struct_decl_members(node, &num_members); + for(size_t i = 0; i < num_members; i++) + { + ast_free_node(members[i]); + } + free(members); + free(node); + break; + } + case AST_UNION_DECL: + { + size_t num_members; + ast_node_t **members = ast_get_union_decl_members(node, &num_members); + for(size_t i = 0; i < num_members; i++) + { + ast_free_node(members[i]); + } + free(members); + free(node); + break; + } + case AST_ENUM_DECL: + { + size_t num_enums; + ast_node_t **enums = ast_get_enum_decl_enums(node, &num_enums); + for(size_t i = 0; i < num_enums; i++) + { + ast_free_node(enums[i]); + } + free(enums); + free(node); + break; + } + case AST_TYPEDEF: + { + ast_node_t *type = ast_get_typedef_type(node); + ast_free_node(type); + free(node); + break; + } + case AST_TYPE: + { + token_t **type; + size_t num_type; + type = ast_get_type(node, &num_type); + for(size_t i = 0; i < num_type; i++) + { + free(type[i]); + } + free(type); + free(node); + break; + } + case AST_MEMBER: + { + ast_node_t *type = ast_get_member_type(node); + ast_free_node(type); + free(node); + break; + } + case AST_ENUM_MEMBER: + { + ast_node_t *value = ast_get_enum_member_expr(node); + ast_free_node(value); + free(node); + break; + } + case AST_TRANSLATION_UNIT: + { + size_t num_items; + ast_node_t **items = ast_get_translation_unit_items(node, &num_items); + for(size_t i = 0; i < num_items; i++) + { + ast_free_node(items[i]); + } + free(items); + free(node); + break; + } + default: + assert(0); + } + +} + + diff --git a/projects/cminus/code/ast.h b/projects/cminus/code/ast.h @@ -0,0 +1,320 @@ +/* ast.h */ +#ifndef AST_H +#define AST_H +#include "token.h" +#include <stddef.h> +#include <stdint.h> +/* Node Types */ +typedef struct ast_node ast_node_t; + +typedef enum { + // Expression nodes + AST_INTU32, + AST_INTU64, + AST_INTS32, + AST_INTS64, + AST_FLOAT, + AST_DOUBLE, + AST_STRING, + AST_CHAR, + AST_VAR, + AST_SUBSCRIPT, + AST_DIRECT_COMPONENT_SELECTION, + AST_INDIRECT_COMPONENT_SELECTION, + AST_FUNCTION_CALL, + AST_POSTFIX_INC, + AST_POSTFIX_DEC, + AST_UNARY_PLUS, + AST_UNARY_MINUS, + AST_LOGICAL_NOT, + AST_BITWISE_NOT, + AST_ADDRESS_OF, + AST_INDIRECTION, + AST_SIZEOF, + AST_PRE_INC, + AST_PRE_DEC, + AST_CAST, + AST_MUL, + AST_DIV, + AST_MOD, + AST_ADD, + AST_SUB, + AST_LEFT_SHIFT, + AST_RIGHT_SHIFT, + AST_LESS_THAN, + AST_GREATER_THAN, + AST_LESS_THAN_OR_EQUAL, + AST_GREATER_THAN_OR_EQUAL, + AST_EQUAL, + AST_NOT_EQUAL, + AST_BITWISE_AND, + AST_BITWISE_XOR, + AST_BITWISE_OR, + AST_LOGICAL_AND, + AST_LOGICAL_OR, + AST_CONDITIONAL, + AST_ASSIGN, + AST_ADD_ASSIGN, + AST_SUB_ASSIGN, + AST_MUL_ASSIGN, + AST_DIV_ASSIGN, + AST_MOD_ASSIGN, + AST_LEFT_SHIFT_ASSIGN, + AST_RIGHT_SHIFT_ASSIGN, + AST_AND_ASSIGN, + AST_XOR_ASSIGN, + AST_OR_ASSIGN, + AST_COMMA, + // Statement nodes + AST_EXPRESSION_STATEMENT, + AST_LABEL_STATEMENT, + AST_CASE_STATEMENT, + AST_DEFAULT_STATEMENT, + AST_COMPOUND_STATEMENT, + AST_IF_STATEMENT, + AST_WHILE_STATEMENT, + AST_DO_WHILE_STATEMENT, + AST_FOR_STATEMENT, + AST_GOTO_STATEMENT, + AST_CONTINUE_STATEMENT, + AST_BREAK_STATEMENT, + AST_RETURN_STATEMENT, + AST_SWITCH_STATEMENT, + AST_NULL_STATEMENT, + // Declaration nodes + AST_VAR_DECL, + AST_FUN_DECL, + AST_PARAM, + AST_FUN_DEF, + AST_STRUCT_DECL, + AST_UNION_DECL, + AST_ENUM_DECL, + AST_TYPEDEF, + AST_TYPE, + AST_MEMBER, + AST_ENUM_MEMBER, + // Translation unit + AST_TRANSLATION_UNIT +} ast_node_type_t; + +/* Node Creation (Expression Nodes) */ +// Expression nodes (primary) +ast_node_t *ast_create_ints32_node(int32_t value, int line, int column); // 1 +ast_node_t *ast_create_ints64_node(int64_t value, int line, int column); // 1L +ast_node_t *ast_create_intu32_node(uint32_t value, int line, int column); // 1u +ast_node_t *ast_create_intu64_node(uint64_t value, int line, int column); // 1ul +ast_node_t *ast_create_float_node(float value, int line, int column); // 1.0f +ast_node_t *ast_create_double_node(double value, int line, int column); // 1.0 +ast_node_t *ast_create_string_node(char *value, int line, int column); // "string" +ast_node_t *ast_create_char_node(char value, int line, int column); // 'c' +ast_node_t *ast_create_var_node(char *value, int line, int column); // Variable +// Nothing needed for paren as the child can just be placed in the parent node directly +// Expression nodes (postfix) +ast_node_t *ast_create_subscript_node(ast_node_t *expr, ast_node_t *subscript, int line, int column); // expr[subscript] +ast_node_t *ast_create_direct_component_selection_node(ast_node_t *expr, char *component, int line, int column); // .component +ast_node_t *ast_create_indirect_component_selection_node(ast_node_t *expr, char *component, int line, int column); // ->component +ast_node_t *ast_create_function_call_node(ast_node_t *expr, ast_node_t **args, size_t num_args, int line, int column); // expr(arg1, arg2, ...) +ast_node_t *ast_create_postfix_inc_node(ast_node_t *expr, int line, int column); // expr++ +ast_node_t *ast_create_postfix_dec_node(ast_node_t *expr, int line, int column); // expr-- +// Expression nodes (unary) +ast_node_t *ast_create_unary_plus_node(ast_node_t *expr, int line, int column); // +expr +ast_node_t *ast_create_unary_minus_node(ast_node_t *expr, int line, int column); // -expr +ast_node_t *ast_create_logical_not_node(ast_node_t *expr, int line, int column); // !expr +ast_node_t *ast_create_bitwise_not_node(ast_node_t *expr, int line, int column); // ~expr +ast_node_t *ast_create_address_of_node(ast_node_t *expr, int line, int column); // &expr +ast_node_t *ast_create_indirection_node(ast_node_t *expr, int line, int column); // *expr +ast_node_t *ast_create_sizeof_node(ast_node_t *expr, int line, int column); // sizeof(expr) +ast_node_t *ast_create_pre_inc_node(ast_node_t *expr, int line, int column); // ++expr +ast_node_t *ast_create_pre_dec_node(ast_node_t *expr, int line, int column); // --expr +// Expression nodes (cast) +ast_node_t *ast_create_cast_node(ast_node_t *type, ast_node_t *expr, int line, int column); // (type)expr +// Expression nodes (multiplicative) +ast_node_t *ast_create_mul_node(ast_node_t *left, ast_node_t *right, int line, int column); // left * right +ast_node_t *ast_create_div_node(ast_node_t *left, ast_node_t *right, int line, int column); // left / right +ast_node_t *ast_create_mod_node(ast_node_t *left, ast_node_t *right, int line, int column); // left % right +// Expression nodes (additive) +ast_node_t *ast_create_add_node(ast_node_t *left, ast_node_t *right, int line, int column); // left + right +ast_node_t *ast_create_sub_node(ast_node_t *left, ast_node_t *right, int line, int column); // left - right +// Expression nodes (shift) +ast_node_t *ast_create_left_shift_node(ast_node_t *left, ast_node_t *right, int line, int column); // left << right +ast_node_t *ast_create_right_shift_node(ast_node_t *left, ast_node_t *right, int line, int column); // left >> right +// Expression nodes (relational) +ast_node_t *ast_create_less_than_node(ast_node_t *left, ast_node_t *right, int line, int column); // left < right +ast_node_t *ast_create_greater_than_node(ast_node_t *left, ast_node_t *right, int line, int column); // left > right +ast_node_t *ast_create_less_than_or_equal_node(ast_node_t *left, ast_node_t *right, int line, int column); // left <= right +ast_node_t *ast_create_greater_than_or_equal_node(ast_node_t *left, ast_node_t *right, int line, int column); // left >= right +// Expression nodes (equality) +ast_node_t *ast_create_equal_node(ast_node_t *left, ast_node_t *right, int line, int column); // left == right +ast_node_t *ast_create_not_equal_node(ast_node_t *left, ast_node_t *right, int line, int column); // left != right +// Expression nodes (bitwise and) +ast_node_t *ast_create_bitwise_and_node(ast_node_t *left, ast_node_t *right, int line, int column); // left & right +// Expression nodes (bitwise xor) +ast_node_t *ast_create_bitwise_xor_node(ast_node_t *left, ast_node_t *right, int line, int column); // left ^ right +// Expression nodes (bitwise or) +ast_node_t *ast_create_bitwise_or_node(ast_node_t *left, ast_node_t *right, int line, int column); // left | right +// Expression nodes (logical and) +ast_node_t *ast_create_logical_and_node(ast_node_t *left, ast_node_t *right, int line, int column); // left && right +// Expression nodes (logical or) +ast_node_t *ast_create_logical_or_node(ast_node_t *left, ast_node_t *right, int line, int column); // left || right +// Expression nodes (conditional) +ast_node_t *ast_create_conditional_node(ast_node_t *condition, ast_node_t *true_expr, ast_node_t *false_expr, int line, int column); // condition ? true_expr : false_expr +// Expression nodes (assignment) +ast_node_t *ast_create_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left = right +ast_node_t *ast_create_add_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left += right +ast_node_t *ast_create_sub_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left -= right +ast_node_t *ast_create_mul_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left *= right +ast_node_t *ast_create_div_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left /= right +ast_node_t *ast_create_mod_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left %= right +ast_node_t *ast_create_left_shift_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left <<= right +ast_node_t *ast_create_right_shift_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left >>= right +ast_node_t *ast_create_and_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left &= right +ast_node_t *ast_create_xor_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left ^= right +ast_node_t *ast_create_or_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left |= right +// Expression nodes (comma) +ast_node_t *ast_create_comma_node(ast_node_t *left, ast_node_t *right, int line, int column); // left, right + +/* Node Creation (Statement Nodes) */ +// Statement nodes (expression) +ast_node_t *ast_create_expression_statement_node(ast_node_t *expr); // expr; +// Statement nodes (label) +ast_node_t *ast_create_label_statement_node(char *label, int line, int column); // label: +ast_node_t *ast_create_case_statement_node(ast_node_t *expr, int line, int column); // case expr: +ast_node_t *ast_create_default_statement_node(int line, int column); // default: +// Statement nodes (compound) +ast_node_t *ast_create_compound_statement_node(ast_node_t **decls_and_stmts, size_t num_decls_and_stmts, int line, int column); // { decls_and_stmts } +// Statement nodes (conditional) +ast_node_t *ast_create_if_statement_node(ast_node_t *condition, ast_node_t *true_stmt, ast_node_t *false_stmt, int line, int column); // if (condition) true_stmt else false_stmt +// Statement nodes (iteration) +ast_node_t *ast_create_while_statement_node(ast_node_t *condition, ast_node_t *stmt, int line, int column); // while (condition) stmt +ast_node_t *ast_create_do_while_statement_node(ast_node_t *stmt, ast_node_t *condition, int line, int column); // do stmt while (condition) +ast_node_t *ast_create_for_statement_node(ast_node_t *init, ast_node_t *condition, ast_node_t *update, ast_node_t *stmt, int line, int column); // for (init; condition; update) stmt +// Statement nodes (jump) +ast_node_t *ast_create_goto_statement_node(char *label, int line, int column); // goto label; +ast_node_t *ast_create_continue_statement_node(int line, int column); // continue; +ast_node_t *ast_create_break_statement_node(int line, int column); // break; +ast_node_t *ast_create_return_statement_node(ast_node_t *expr, int line, int column); // return expr; +// Statement nodes (multiway branch) +ast_node_t *ast_create_switch_statement_node(ast_node_t *expr, ast_node_t *stmt, int line, int column); // switch (expr) stmt +// Statement nodes (null) +ast_node_t *ast_create_null_statement_node(int line, int column); // ; + +/* Node Creation (Declaration Nodes) */ +// Declaration nodes (simple) +ast_node_t *ast_create_var_decl_node(ast_node_t *type, char *id, int line, int column); // type id +ast_node_t *ast_create_fun_decl_node(ast_node_t *type, char *id, ast_node_t **params, size_t num_params, int line, int column); // type id(params) +// Declaration nodes (parameter) +ast_node_t *ast_create_param_node(ast_node_t *type, char *id, int line, int column); // type id +// Declaration nodes (function) +ast_node_t *ast_create_fun_def_node(ast_node_t *type, char *id, ast_node_t **params, size_t num_params, ast_node_t *stmt, int line, int column); // type id(params) stmt +// Declaration nodes (struct) +ast_node_t *ast_create_struct_decl_node(char *id, ast_node_t **members, size_t num_members, int line, int column); // struct id { members } (reuses param node for members) +// Declaration nodes (union) +ast_node_t *ast_create_union_decl_node(char *id, ast_node_t **members, size_t num_members, int line, int column); // union id { members } (reuses param node for members) +// Declaration nodes (enum) +ast_node_t *ast_create_enum_decl_node(char *id, ast_node_t **enums, size_t num_enums, int line, int column); // enum id { enums } +// Declaration nodes (Typedef) +ast_node_t *ast_create_typedef_node(ast_node_t *type, char *id, int line, int column); // typedef type id +// Types/members +ast_node_t *ast_create_type_node(token_t *type[], size_t num_type, int line, int column); // type +ast_node_t *ast_create_member_node(ast_node_t *type, char *id, int line, int column); // type id +ast_node_t *ast_create_enum_member_node(char *id, ast_node_t *value, int line, int column); // id = value + +/* Node Creation (Translation Unit) */ +ast_node_t *ast_create_translation_unit(ast_node_t **nodes, size_t num_nodes, int line, int column); + +/* Node Destruction */ +void ast_destroy_node(ast_node_t *node); + +/* Node Information (General) */ +ast_node_type_t ast_get_node_type(ast_node_t *node); +int ast_get_node_line(ast_node_t *node); +int ast_get_node_column(ast_node_t *node); + +/* Node Information (Expression Nodes) */ +// Expression nodes (primary) +int64_t ast_get_int_value(ast_node_t *node); +double ast_get_double_value(ast_node_t *node); +char *ast_get_string_value(ast_node_t *node); +char ast_get_char_value(ast_node_t *node); +char *ast_get_var_value(ast_node_t *node); +// Expression nodes (postfix) +ast_node_t *ast_get_subscript_expr(ast_node_t *node); +ast_node_t *ast_get_subscript_idx(ast_node_t *node); +char *ast_get_component(ast_node_t *node); +ast_node_t *ast_get_function_call_expr(ast_node_t *node); +ast_node_t **ast_get_function_call_args(ast_node_t *node, size_t *num_args); +ast_node_t *ast_get_postfix_expr(ast_node_t *node); +// Expression nodes (unary) +ast_node_t *ast_get_unary_expr(ast_node_t *node); +// Expression nodes (cast) +ast_node_t *ast_get_cast_type(ast_node_t *node); +ast_node_t *ast_get_cast_expr(ast_node_t *node); +// Expression nodes (binary) +ast_node_t *ast_get_left_expr(ast_node_t *node); +ast_node_t *ast_get_right_expr(ast_node_t *node); +// Expression nodes (conditional) +ast_node_t *ast_get_conditional_condition(ast_node_t *node); +ast_node_t *ast_get_conditional_true_expr(ast_node_t *node); +ast_node_t *ast_get_conditional_false_expr(ast_node_t *node); + +/* Node Information (Statement Nodes) */ +// Statement nodes (expression) +ast_node_t *ast_get_expression_statement_expr(ast_node_t *node); +// Statement nodes (label) +char *ast_get_label_statement_label(ast_node_t *node); // label +ast_node_t *ast_get_case_statement_expr(ast_node_t *node); // expr +// Statement nodes (compound) +ast_node_t **ast_get_compound_statement_contents(ast_node_t *node, size_t *num_contents); // decls_and_stmts +// Statement nodes (conditional) +ast_node_t *ast_get_if_statement_condition(ast_node_t *node); // condition +ast_node_t *ast_get_if_statement_true_stmt(ast_node_t *node); // true_stmt +ast_node_t *ast_get_if_statement_false_stmt(ast_node_t *node); // false_stmt +// Statement nodes (iteration) +ast_node_t *ast_get_iteration_statement_condition(ast_node_t *node); // condition +ast_node_t *ast_get_iteration_statement_stmt(ast_node_t *node); // stmt +ast_node_t *ast_get_for_statement_init(ast_node_t *node); // init +ast_node_t *ast_get_for_statement_update(ast_node_t *node); // update +// Statement nodes (jump) +char *ast_get_goto_statement_label(ast_node_t *node); // label +// Statement nodes (multiway branch) +ast_node_t *ast_get_switch_statement_expr(ast_node_t *node); // expr +ast_node_t *ast_get_switch_statement_stmt(ast_node_t *node); // stmt + +/* Node Information (Declaration Nodes) */ +// Declaration nodes (simple) +ast_node_t *ast_get_var_decl_type(ast_node_t *node); +char *ast_get_var_decl_id(ast_node_t *node); +ast_node_t *ast_get_fun_decl_type(ast_node_t *node); +char *ast_get_fun_decl_id(ast_node_t *node); +ast_node_t **ast_get_fun_decl_params(ast_node_t *node, size_t *num_params); +// Declaration nodes (parameter) +ast_node_t *ast_get_param_type(ast_node_t *node); +char *ast_get_param_id(ast_node_t *node); +// Declaration nodes (function) +ast_node_t *ast_get_fun_def_type(ast_node_t *node); +char *ast_get_fun_def_id(ast_node_t *node); +ast_node_t **ast_get_fun_def_params(ast_node_t *node, size_t *num_params); +ast_node_t *ast_get_fun_def_stmt(ast_node_t *node); +// Declaration nodes (struct) +char *ast_get_struct_decl_id(ast_node_t *node); +ast_node_t **ast_get_struct_decl_members(ast_node_t *node, size_t *num_members); +// Declaration nodes (union) +char *ast_get_union_decl_id(ast_node_t *node); +ast_node_t **ast_get_union_decl_members(ast_node_t *node, size_t *num_members); +// Declaration nodes (enum) +char *ast_get_enum_decl_id(ast_node_t *node); +ast_node_t **ast_get_enum_decl_enums(ast_node_t *node, size_t *num_enums); +// Declaration nodes (Typedef) +ast_node_t *ast_get_typedef_type(ast_node_t *node); +char *ast_get_typedef_id(ast_node_t *node); +// Types/members +token_t **ast_get_type(ast_node_t *node, size_t *num_type); +ast_node_t *ast_get_member_type(ast_node_t *node); +char *ast_get_member_id(ast_node_t *node); +ast_node_t *ast_get_enum_member_expr(ast_node_t *node); + +/* Node Information (Translation Unit) */ +ast_node_t **ast_get_translation_unit(ast_node_t *node, size_t *num_nodes); + +#endif + diff --git a/projects/cminus/code/ast.lit b/projects/cminus/code/ast.lit @@ -0,0 +1,1897 @@ +@code_type c .c +@comment_type /* %s */ +@compiler lit -t ast.lit && gcc -Wall -Wextra -Wstrict-aliasing=3 -Wwrite-strings -Wvla -Wcast-align=strict -Wstrict-prototypes -Wstringop-overflow=4 -fanalyzer -c ast.c -g -O0 -o ast.o + +@title AST code +@add_css ./style.css + +@s +This is the AST code. There's no important logic here, this is just accessors and constructors for the AST nodes + +@s The AST Interface - Node Types + +--- Node Types +typedef struct ast_node ast_node_t; + +typedef enum { + // Expression nodes + AST_INTU32, + AST_INTU64, + AST_INTS32, + AST_INTS64, + AST_FLOAT, + AST_DOUBLE, + AST_STRING, + AST_CHAR, + AST_VAR, + AST_SUBSCRIPT, + AST_DIRECT_COMPONENT_SELECTION, + AST_INDIRECT_COMPONENT_SELECTION, + AST_FUNCTION_CALL, + AST_POSTFIX_INC, + AST_POSTFIX_DEC, + AST_UNARY_PLUS, + AST_UNARY_MINUS, + AST_LOGICAL_NOT, + AST_BITWISE_NOT, + AST_ADDRESS_OF, + AST_INDIRECTION, + AST_SIZEOF, + AST_PRE_INC, + AST_PRE_DEC, + AST_CAST, + AST_MUL, + AST_DIV, + AST_MOD, + AST_ADD, + AST_SUB, + AST_LEFT_SHIFT, + AST_RIGHT_SHIFT, + AST_LESS_THAN, + AST_GREATER_THAN, + AST_LESS_THAN_OR_EQUAL, + AST_GREATER_THAN_OR_EQUAL, + AST_EQUAL, + AST_NOT_EQUAL, + AST_BITWISE_AND, + AST_BITWISE_XOR, + AST_BITWISE_OR, + AST_LOGICAL_AND, + AST_LOGICAL_OR, + AST_CONDITIONAL, + AST_ASSIGN, + AST_ADD_ASSIGN, + AST_SUB_ASSIGN, + AST_MUL_ASSIGN, + AST_DIV_ASSIGN, + AST_MOD_ASSIGN, + AST_LEFT_SHIFT_ASSIGN, + AST_RIGHT_SHIFT_ASSIGN, + AST_AND_ASSIGN, + AST_XOR_ASSIGN, + AST_OR_ASSIGN, + AST_COMMA, + // Statement nodes + AST_EXPRESSION_STATEMENT, + AST_LABEL_STATEMENT, + AST_CASE_STATEMENT, + AST_DEFAULT_STATEMENT, + AST_COMPOUND_STATEMENT, + AST_IF_STATEMENT, + AST_WHILE_STATEMENT, + AST_DO_WHILE_STATEMENT, + AST_FOR_STATEMENT, + AST_GOTO_STATEMENT, + AST_CONTINUE_STATEMENT, + AST_BREAK_STATEMENT, + AST_RETURN_STATEMENT, + AST_SWITCH_STATEMENT, + AST_NULL_STATEMENT, + // Declaration nodes + AST_VAR_DECL, + AST_FUN_DECL, + AST_PARAM, + AST_FUN_DEF, + AST_STRUCT_DECL, + AST_UNION_DECL, + AST_ENUM_DECL, + AST_TYPEDEF, + AST_TYPE, + AST_MEMBER, + AST_ENUM_MEMBER, + // Translation unit + AST_TRANSLATION_UNIT +} ast_node_type_t; +--- + +@s The AST Interface - Creating Nodes +These functions create nodes for the AST. + +The order of functions here partly follows the order of the grammar rules from the bottom up, I.E primary -> postfix -> unary -> multiplicative -> additive -> relational -> equality -> assignment -> expression -> statement -> declaration. +--- Node Creation (Expression Nodes) +// Expression nodes (primary) +ast_node_t *ast_create_ints32_node(int32_t value, int line, int column); // 1 +ast_node_t *ast_create_ints64_node(int64_t value, int line, int column); // 1L +ast_node_t *ast_create_intu32_node(uint32_t value, int line, int column); // 1u +ast_node_t *ast_create_intu64_node(uint64_t value, int line, int column); // 1ul +ast_node_t *ast_create_float_node(float value, int line, int column); // 1.0f +ast_node_t *ast_create_double_node(double value, int line, int column); // 1.0 +ast_node_t *ast_create_string_node(char *value, int line, int column); // "string" +ast_node_t *ast_create_char_node(char value, int line, int column); // 'c' +ast_node_t *ast_create_var_node(char *value, int line, int column); // Variable +// Nothing needed for paren as the child can just be placed in the parent node directly +// Expression nodes (postfix) +ast_node_t *ast_create_subscript_node(ast_node_t *expr, ast_node_t *subscript, int line, int column); // expr[subscript] +ast_node_t *ast_create_direct_component_selection_node(ast_node_t *expr, char *component, int line, int column); // .component +ast_node_t *ast_create_indirect_component_selection_node(ast_node_t *expr, char *component, int line, int column); // ->component +ast_node_t *ast_create_function_call_node(ast_node_t *expr, ast_node_t **args, size_t num_args, int line, int column); // expr(arg1, arg2, ...) +ast_node_t *ast_create_postfix_inc_node(ast_node_t *expr, int line, int column); // expr++ +ast_node_t *ast_create_postfix_dec_node(ast_node_t *expr, int line, int column); // expr-- +// Expression nodes (unary) +ast_node_t *ast_create_unary_plus_node(ast_node_t *expr, int line, int column); // +expr +ast_node_t *ast_create_unary_minus_node(ast_node_t *expr, int line, int column); // -expr +ast_node_t *ast_create_logical_not_node(ast_node_t *expr, int line, int column); // !expr +ast_node_t *ast_create_bitwise_not_node(ast_node_t *expr, int line, int column); // ~expr +ast_node_t *ast_create_address_of_node(ast_node_t *expr, int line, int column); // &expr +ast_node_t *ast_create_indirection_node(ast_node_t *expr, int line, int column); // *expr +ast_node_t *ast_create_sizeof_node(ast_node_t *expr, int line, int column); // sizeof(expr) +ast_node_t *ast_create_pre_inc_node(ast_node_t *expr, int line, int column); // ++expr +ast_node_t *ast_create_pre_dec_node(ast_node_t *expr, int line, int column); // --expr +// Expression nodes (cast) +ast_node_t *ast_create_cast_node(ast_node_t *type, ast_node_t *expr, int line, int column); // (type)expr +// Expression nodes (multiplicative) +ast_node_t *ast_create_mul_node(ast_node_t *left, ast_node_t *right, int line, int column); // left * right +ast_node_t *ast_create_div_node(ast_node_t *left, ast_node_t *right, int line, int column); // left / right +ast_node_t *ast_create_mod_node(ast_node_t *left, ast_node_t *right, int line, int column); // left % right +// Expression nodes (additive) +ast_node_t *ast_create_add_node(ast_node_t *left, ast_node_t *right, int line, int column); // left + right +ast_node_t *ast_create_sub_node(ast_node_t *left, ast_node_t *right, int line, int column); // left - right +// Expression nodes (shift) +ast_node_t *ast_create_left_shift_node(ast_node_t *left, ast_node_t *right, int line, int column); // left << right +ast_node_t *ast_create_right_shift_node(ast_node_t *left, ast_node_t *right, int line, int column); // left >> right +// Expression nodes (relational) +ast_node_t *ast_create_less_than_node(ast_node_t *left, ast_node_t *right, int line, int column); // left < right +ast_node_t *ast_create_greater_than_node(ast_node_t *left, ast_node_t *right, int line, int column); // left > right +ast_node_t *ast_create_less_than_or_equal_node(ast_node_t *left, ast_node_t *right, int line, int column); // left <= right +ast_node_t *ast_create_greater_than_or_equal_node(ast_node_t *left, ast_node_t *right, int line, int column); // left >= right +// Expression nodes (equality) +ast_node_t *ast_create_equal_node(ast_node_t *left, ast_node_t *right, int line, int column); // left == right +ast_node_t *ast_create_not_equal_node(ast_node_t *left, ast_node_t *right, int line, int column); // left != right +// Expression nodes (bitwise and) +ast_node_t *ast_create_bitwise_and_node(ast_node_t *left, ast_node_t *right, int line, int column); // left & right +// Expression nodes (bitwise xor) +ast_node_t *ast_create_bitwise_xor_node(ast_node_t *left, ast_node_t *right, int line, int column); // left ^ right +// Expression nodes (bitwise or) +ast_node_t *ast_create_bitwise_or_node(ast_node_t *left, ast_node_t *right, int line, int column); // left | right +// Expression nodes (logical and) +ast_node_t *ast_create_logical_and_node(ast_node_t *left, ast_node_t *right, int line, int column); // left && right +// Expression nodes (logical or) +ast_node_t *ast_create_logical_or_node(ast_node_t *left, ast_node_t *right, int line, int column); // left || right +// Expression nodes (conditional) +ast_node_t *ast_create_conditional_node(ast_node_t *condition, ast_node_t *true_expr, ast_node_t *false_expr, int line, int column); // condition ? true_expr : false_expr +// Expression nodes (assignment) +ast_node_t *ast_create_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left = right +ast_node_t *ast_create_add_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left += right +ast_node_t *ast_create_sub_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left -= right +ast_node_t *ast_create_mul_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left *= right +ast_node_t *ast_create_div_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left /= right +ast_node_t *ast_create_mod_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left %= right +ast_node_t *ast_create_left_shift_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left <<= right +ast_node_t *ast_create_right_shift_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left >>= right +ast_node_t *ast_create_and_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left &= right +ast_node_t *ast_create_xor_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left ^= right +ast_node_t *ast_create_or_assign_node(ast_node_t *left, ast_node_t *right, int line, int column); // left |= right +// Expression nodes (comma) +ast_node_t *ast_create_comma_node(ast_node_t *left, ast_node_t *right, int line, int column); // left, right +--- + +@s +Here we define functions for creating statement nodes. +--- Node Creation (Statement Nodes) +// Statement nodes (expression) +ast_node_t *ast_create_expression_statement_node(ast_node_t *expr); // expr; +// Statement nodes (label) +ast_node_t *ast_create_label_statement_node(char *label, int line, int column); // label: +ast_node_t *ast_create_case_statement_node(ast_node_t *expr, int line, int column); // case expr: +ast_node_t *ast_create_default_statement_node(int line, int column); // default: +// Statement nodes (compound) +ast_node_t *ast_create_compound_statement_node(ast_node_t **decls_and_stmts, size_t num_decls_and_stmts, int line, int column); // { decls_and_stmts } +// Statement nodes (conditional) +ast_node_t *ast_create_if_statement_node(ast_node_t *condition, ast_node_t *true_stmt, ast_node_t *false_stmt, int line, int column); // if (condition) true_stmt else false_stmt +// Statement nodes (iteration) +ast_node_t *ast_create_while_statement_node(ast_node_t *condition, ast_node_t *stmt, int line, int column); // while (condition) stmt +ast_node_t *ast_create_do_while_statement_node(ast_node_t *stmt, ast_node_t *condition, int line, int column); // do stmt while (condition) +ast_node_t *ast_create_for_statement_node(ast_node_t *init, ast_node_t *condition, ast_node_t *update, ast_node_t *stmt, int line, int column); // for (init; condition; update) stmt +// Statement nodes (jump) +ast_node_t *ast_create_goto_statement_node(char *label, int line, int column); // goto label; +ast_node_t *ast_create_continue_statement_node(int line, int column); // continue; +ast_node_t *ast_create_break_statement_node(int line, int column); // break; +ast_node_t *ast_create_return_statement_node(ast_node_t *expr, int line, int column); // return expr; +// Statement nodes (multiway branch) +ast_node_t *ast_create_switch_statement_node(ast_node_t *expr, ast_node_t *stmt, int line, int column); // switch (expr) stmt +// Statement nodes (null) +ast_node_t *ast_create_null_statement_node(int line, int column); // ; +--- + +@s +Here we define functions for creating declaration nodes. Types are passed as a raw list of tokens, which will be used in the semantic analysis phase to build a type. In this way, we're kind of offsetting type parsing. + +An example call for a declaration would be `ast_node_t *type = ast_create_type_node((token_t *[]){ptr to TOK_VOLATILE, ptr to TOK_CONST, ptr to TOK_INT}, 3);`, `ast_node_t *decl = ast_create_var_decl_node(type, "x");`. + +A special AST node is created for parameters, struct/union members, and enum members. The enum member node can hold a value, but the others are just for the type. +A special AST node also exists for types. +--- Node Creation (Declaration Nodes) +// Declaration nodes (simple) +ast_node_t *ast_create_var_decl_node(ast_node_t *type, char *id, int line, int column); // type id +ast_node_t *ast_create_fun_decl_node(ast_node_t *type, char *id, ast_node_t **params, size_t num_params, int line, int column); // type id(params) +// Declaration nodes (parameter) +ast_node_t *ast_create_param_node(ast_node_t *type, char *id, int line, int column); // type id +// Declaration nodes (function) +ast_node_t *ast_create_fun_def_node(ast_node_t *type, char *id, ast_node_t **params, size_t num_params, ast_node_t *stmt, int line, int column); // type id(params) stmt +// Declaration nodes (struct) +ast_node_t *ast_create_struct_decl_node(char *id, ast_node_t **members, size_t num_members, int line, int column); // struct id { members } (reuses param node for members) +// Declaration nodes (union) +ast_node_t *ast_create_union_decl_node(char *id, ast_node_t **members, size_t num_members, int line, int column); // union id { members } (reuses param node for members) +// Declaration nodes (enum) +ast_node_t *ast_create_enum_decl_node(char *id, ast_node_t **enums, size_t num_enums, int line, int column); // enum id { enums } +// Declaration nodes (Typedef) +ast_node_t *ast_create_typedef_node(ast_node_t *type, char *id, int line, int column); // typedef type id +// Types/members +ast_node_t *ast_create_type_node(token_t *type[], size_t num_type, int line, int column); // type +ast_node_t *ast_create_member_node(ast_node_t *type, char *id, int line, int column); // type id +ast_node_t *ast_create_enum_member_node(char *id, ast_node_t *value, int line, int column); // id = value +--- + +@s The AST Interface - Translation Unit +The translation unit is the root of the AST. It's a list of nodes, which can be declarations or statements. This is the only function that will be called from the parser. +--- Node Creation (Translation Unit) +ast_node_t *ast_create_translation_unit(ast_node_t **nodes, size_t num_nodes, int line, int column); +--- +@s The AST Interface - Destroying Nodes +A single function is defined to destroy an AST node and all its children. +--- Node Destruction +void ast_destroy_node(ast_node_t *node); +--- + +@s The AST Interface - Getting Node Information +These functions get information from the AST nodes. They will do on-the-fly type checking to ensure the node is the correct type, so we need to have separate functions for each type of node. + +@s +--- Node Information (General) +ast_node_type_t ast_get_node_type(ast_node_t *node); +int ast_get_node_line(ast_node_t *node); +int ast_get_node_column(ast_node_t *node); +--- + +@s +--- Node Information (Expression Nodes) +// Expression nodes (primary) +int64_t ast_get_int_value(ast_node_t *node); +double ast_get_double_value(ast_node_t *node); +char *ast_get_string_value(ast_node_t *node); +char ast_get_char_value(ast_node_t *node); +char *ast_get_var_value(ast_node_t *node); +// Expression nodes (postfix) +ast_node_t *ast_get_subscript_expr(ast_node_t *node); +ast_node_t *ast_get_subscript_idx(ast_node_t *node); +char *ast_get_component(ast_node_t *node); +ast_node_t *ast_get_function_call_expr(ast_node_t *node); +ast_node_t **ast_get_function_call_args(ast_node_t *node, size_t *num_args); +ast_node_t *ast_get_postfix_expr(ast_node_t *node); +// Expression nodes (unary) +ast_node_t *ast_get_unary_expr(ast_node_t *node); +// Expression nodes (cast) +ast_node_t *ast_get_cast_type(ast_node_t *node); +ast_node_t *ast_get_cast_expr(ast_node_t *node); +// Expression nodes (binary) +ast_node_t *ast_get_left_expr(ast_node_t *node); +ast_node_t *ast_get_right_expr(ast_node_t *node); +// Expression nodes (conditional) +ast_node_t *ast_get_conditional_condition(ast_node_t *node); +ast_node_t *ast_get_conditional_true_expr(ast_node_t *node); +ast_node_t *ast_get_conditional_false_expr(ast_node_t *node); +--- + +@s +--- Node Information (Statement Nodes) +// Statement nodes (expression) +ast_node_t *ast_get_expression_statement_expr(ast_node_t *node); +// Statement nodes (label) +char *ast_get_label_statement_label(ast_node_t *node); // label +ast_node_t *ast_get_case_statement_expr(ast_node_t *node); // expr +// Statement nodes (compound) +ast_node_t **ast_get_compound_statement_contents(ast_node_t *node, size_t *num_contents); // decls_and_stmts +// Statement nodes (conditional) +ast_node_t *ast_get_if_statement_condition(ast_node_t *node); // condition +ast_node_t *ast_get_if_statement_true_stmt(ast_node_t *node); // true_stmt +ast_node_t *ast_get_if_statement_false_stmt(ast_node_t *node); // false_stmt +// Statement nodes (iteration) +ast_node_t *ast_get_iteration_statement_condition(ast_node_t *node); // condition +ast_node_t *ast_get_iteration_statement_stmt(ast_node_t *node); // stmt +ast_node_t *ast_get_for_statement_init(ast_node_t *node); // init +ast_node_t *ast_get_for_statement_update(ast_node_t *node); // update +// Statement nodes (jump) +char *ast_get_goto_statement_label(ast_node_t *node); // label +// Statement nodes (multiway branch) +ast_node_t *ast_get_switch_statement_expr(ast_node_t *node); // expr +ast_node_t *ast_get_switch_statement_stmt(ast_node_t *node); // stmt +--- + +@s +--- Node Information (Declaration Nodes) +// Declaration nodes (simple) +ast_node_t *ast_get_var_decl_type(ast_node_t *node); +char *ast_get_var_decl_id(ast_node_t *node); +ast_node_t *ast_get_fun_decl_type(ast_node_t *node); +char *ast_get_fun_decl_id(ast_node_t *node); +ast_node_t **ast_get_fun_decl_params(ast_node_t *node, size_t *num_params); +// Declaration nodes (parameter) +ast_node_t *ast_get_param_type(ast_node_t *node); +char *ast_get_param_id(ast_node_t *node); +// Declaration nodes (function) +ast_node_t *ast_get_fun_def_type(ast_node_t *node); +char *ast_get_fun_def_id(ast_node_t *node); +ast_node_t **ast_get_fun_def_params(ast_node_t *node, size_t *num_params); +ast_node_t *ast_get_fun_def_stmt(ast_node_t *node); +// Declaration nodes (struct) +char *ast_get_struct_decl_id(ast_node_t *node); +ast_node_t **ast_get_struct_decl_members(ast_node_t *node, size_t *num_members); +// Declaration nodes (union) +char *ast_get_union_decl_id(ast_node_t *node); +ast_node_t **ast_get_union_decl_members(ast_node_t *node, size_t *num_members); +// Declaration nodes (enum) +char *ast_get_enum_decl_id(ast_node_t *node); +ast_node_t **ast_get_enum_decl_enums(ast_node_t *node, size_t *num_enums); +// Declaration nodes (Typedef) +ast_node_t *ast_get_typedef_type(ast_node_t *node); +char *ast_get_typedef_id(ast_node_t *node); +// Types/members +token_t **ast_get_type(ast_node_t *node, size_t *num_type); +ast_node_t *ast_get_member_type(ast_node_t *node); +char *ast_get_member_id(ast_node_t *node); +ast_node_t *ast_get_enum_member_expr(ast_node_t *node); +--- + +@s + +--- Node Information (Translation Unit) +ast_node_t **ast_get_translation_unit(ast_node_t *node, size_t *num_nodes); +--- + +@s +Having seperate calls for each type makes it very difficult to mess up the tree structure in the parser. + +@s + +--- ast.h +#ifndef AST_H +#define AST_H +#include "token.h" +#include <stddef.h> +#include <stdint.h> +@{Node Types} +@{Node Creation (Expression Nodes)} +@{Node Creation (Statement Nodes)} +@{Node Creation (Declaration Nodes)} +@{Node Creation (Translation Unit)} +@{Node Destruction} +@{Node Information (General)} +@{Node Information (Expression Nodes)} +@{Node Information (Statement Nodes)} +@{Node Information (Declaration Nodes)} +@{Node Information (Translation Unit)} +#endif +--- + +--- Implementation - Common Node Structure +#define AST_MAGIC 0x4153544E4F44ULL // "ASTNOD" + +struct ast_node { + long magic; + int line; + int column; + int hasdata; + short kind; + long opt_data[0]; +}; + +static void* ast_get_data(ast_node_t *node) +{ + assert(node->magic == AST_MAGIC); + assert(node->hasdata); + return node->opt_data; +} + +ast_node_type_t ast_get_node_type(ast_node_t *node) +{ + assert(node->magic == AST_MAGIC); + return node->kind; +} + +int ast_get_node_line(ast_node_t *node) +{ + assert(node->magic == AST_MAGIC); + return node->line; +} + +int ast_get_node_column(ast_node_t *node) +{ + assert(node->magic == AST_MAGIC); + return node->column; +} + +static ast_node_t *ast_create_node(ast_node_type_t kind, int line, int column, size_t data_size) +{ + ast_node_t *node = malloc(sizeof(ast_node_t) + data_size); + node->magic = AST_MAGIC; + node->line = line; + node->column = column; + node->hasdata = data_size > 0; + node->kind = kind; + return node; +} +--- + + + +@s +--- Implementation - Nodes (Primary) +struct ast_int_node { + int64_t value; +}; + +ast_node_t *ast_create_intu32_node(uint32_t value, int line, int column) +{ + ast_node_t *node = + ast_create_node(AST_INTU32, line, column, sizeof(struct ast_int_node)); + struct ast_int_node *data = ast_get_data(node); + data->value = value; + return node; +} + +ast_node_t *ast_create_ints32_node(int32_t value, int line, int column) +{ + ast_node_t *node = + ast_create_node(AST_INTS32, line, column, sizeof(struct ast_int_node)); + struct ast_int_node *data = ast_get_data(node); + data->value = value; + return node; +} + +ast_node_t *ast_create_intu64_node(uint64_t value, int line, int column) +{ + ast_node_t *node = + ast_create_node(AST_INTU64, line, column, sizeof(struct ast_int_node)); + struct ast_int_node *data = ast_get_data(node); + data->value = value; + return node; +} + +ast_node_t *ast_create_ints64_node(int64_t value, int line, int column) +{ + ast_node_t *node = + ast_create_node(AST_INTS64, line, column, sizeof(struct ast_int_node)); + struct ast_int_node *data = ast_get_data(node); + data->value = value; + return node; +} + +int64_t ast_get_int_value(ast_node_t *node) { + assert(ast_get_node_type(node) == AST_INTU32 || ast_get_node_type(node) == AST_INTS32 || ast_get_node_type(node) == AST_INTU64 || ast_get_node_type(node) == AST_INTS64); + struct ast_int_node *data = ast_get_data(node); + return data->value; +} + +struct ast_double_node { + double value; +}; + +struct ast_float_node { + float value; +}; + +ast_node_t *ast_create_float_node(float value, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_FLOAT, line, column, sizeof(struct ast_float_node)); + struct ast_float_node *data = ast_get_data(node); + data->value = value; + return node; +} + +float ast_get_float_value(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_FLOAT); + struct ast_float_node *data = ast_get_data(node); + return data->value; +} + +ast_node_t *ast_create_double_node(double value, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_DOUBLE, line, column, sizeof(struct ast_double_node)); + struct ast_double_node *data = ast_get_data(node); + data->value = value; + return node; +} + +double ast_get_double_value(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_DOUBLE); + struct ast_double_node *data = ast_get_data(node); + return data->value; +} + +struct ast_string_node { + char *value; +}; + +ast_node_t *ast_create_string_node(char *value, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_STRING, line, column, sizeof(struct ast_string_node)); + struct ast_string_node *data = ast_get_data(node); + data->value = value; // We don't duplicate here because the string is in the shared string table + return node; +} + +char *ast_get_string_value(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_STRING); + struct ast_string_node *data = ast_get_data(node); + return data->value; +} + +struct ast_char_node { + char value; +}; + +ast_node_t *ast_create_char_node(char value, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_CHAR, line, column, sizeof(struct ast_char_node)); + struct ast_char_node *data = ast_get_data(node); + data->value = value; + return node; +} + +char ast_get_char_value(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CHAR); + struct ast_char_node *data = ast_get_data(node); + return data->value; +} + +ast_node_t *ast_create_var_node(char *value, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_VAR, line, column, sizeof(struct ast_string_node)); + struct ast_string_node *data = ast_get_data(node); + data->value = value; // We don't duplicate here because the string is in the shared string table + return node; +} + +char *ast_get_var_value(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_VAR); + struct ast_string_node *data = ast_get_data(node); + return data->value; +} +--- + +@s + +--- Implementation - Nodes (Postfix) +struct ast_subscript_node { + ast_node_t *expr; + ast_node_t *subscript; +}; + +ast_node_t *ast_create_subscript_node(ast_node_t *expr, ast_node_t *subscript, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_SUBSCRIPT, line, column, sizeof(struct ast_subscript_node)); + struct ast_subscript_node *data = ast_get_data(node); + data->expr = expr; + data->subscript = subscript; + return node; +} + +ast_node_t *ast_get_subscript_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_SUBSCRIPT); + struct ast_subscript_node *data = ast_get_data(node); + return data->expr; +} + +ast_node_t *ast_get_subscript_idx(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_SUBSCRIPT); + struct ast_subscript_node *data = ast_get_data(node); + return data->subscript; +} + +struct ast_component_selection_node { + ast_node_t *expr; + char *component; +}; + +ast_node_t *ast_create_direct_component_selection_node(ast_node_t *expr, char *component, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_DIRECT_COMPONENT_SELECTION, line, column, sizeof(struct ast_component_selection_node)); + struct ast_component_selection_node *data = ast_get_data(node); + data->expr = expr; + data->component = component; + return node; +} + +char *ast_get_component(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_DIRECT_COMPONENT_SELECTION); + struct ast_component_selection_node *data = ast_get_data(node); + return data->component; +} + +ast_node_t *ast_get_component_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_DIRECT_COMPONENT_SELECTION); + struct ast_component_selection_node *data = ast_get_data(node); + return data->expr; +} + +ast_node_t *ast_create_indirect_component_selection_node(ast_node_t *expr, char *component, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_INDIRECT_COMPONENT_SELECTION, line, column, sizeof(struct ast_component_selection_node)); + struct ast_component_selection_node *data = ast_get_data(node); + data->expr = expr; + data->component = component; + return node; +} + +struct ast_function_call_node { + ast_node_t *expr; + ast_node_t **args; + size_t num_args; +}; + +ast_node_t *ast_create_function_call_node(ast_node_t *expr, ast_node_t **args, size_t num_args, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_FUNCTION_CALL, line, column, sizeof(struct ast_function_call_node)); + struct ast_function_call_node *data = ast_get_data(node); + data->expr = expr; + data->args = args; + data->num_args = num_args; + return node; +} + +ast_node_t *ast_get_function_call_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_FUNCTION_CALL); + struct ast_function_call_node *data = ast_get_data(node); + return data->expr; +} + +ast_node_t **ast_get_function_call_args(ast_node_t *node, size_t *num_args) +{ + assert(ast_get_node_type(node) == AST_FUNCTION_CALL); + struct ast_function_call_node *data = ast_get_data(node); + *num_args = data->num_args; + return data->args; +} + +ast_node_t *ast_create_postfix_inc_node(ast_node_t *expr, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_POSTFIX_INC, line, column, sizeof(ast_node_t *)); + ast_node_t **data = ast_get_data(node); + *data = expr; + return node; +} + +ast_node_t *ast_create_postfix_dec_node(ast_node_t *expr, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_POSTFIX_DEC, line, column, sizeof(ast_node_t *)); + ast_node_t **data = ast_get_data(node); + *data = expr; + return node; +} + +ast_node_t *ast_get_postfix_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_POSTFIX_INC || ast_get_node_type(node) == AST_POSTFIX_DEC); + ast_node_t **data = ast_get_data(node); + return *data; +} +--- + +@s + +--- Implementation - Nodes (Unary/Cast) + +#define AST_CREATE_UNARY_NODE(NODE_TYPE, NODE_NAME) \ +ast_node_t *ast_create_##NODE_NAME##_node(ast_node_t *expr, int line, int column) \ +{ \ + ast_node_t *node = ast_create_node(NODE_TYPE, line, column, sizeof(ast_node_t *)); \ + ast_node_t **data = ast_get_data(node); \ + *data = expr; \ + return node; \ +} + +AST_CREATE_UNARY_NODE(AST_UNARY_PLUS, unary_plus) +AST_CREATE_UNARY_NODE(AST_UNARY_MINUS, unary_minus) +AST_CREATE_UNARY_NODE(AST_LOGICAL_NOT, logical_not) +AST_CREATE_UNARY_NODE(AST_BITWISE_NOT, bitwise_not) +AST_CREATE_UNARY_NODE(AST_ADDRESS_OF, address_of) +AST_CREATE_UNARY_NODE(AST_INDIRECTION, indirection) +AST_CREATE_UNARY_NODE(AST_SIZEOF, sizeof) +AST_CREATE_UNARY_NODE(AST_PRE_INC, pre_inc) +AST_CREATE_UNARY_NODE(AST_PRE_DEC, pre_dec) + +ast_node_t *ast_create_cast_node(ast_node_t *type, ast_node_t *expr, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_CAST, line, column, 2 * sizeof(ast_node_t *)); + ast_node_t **data = ast_get_data(node); + data[0] = type; + data[1] = expr; + return node; +} + +ast_node_t *ast_get_unary_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_UNARY_PLUS || ast_get_node_type(node) == AST_UNARY_MINUS || ast_get_node_type(node) == AST_LOGICAL_NOT || ast_get_node_type(node) == AST_BITWISE_NOT || ast_get_node_type(node) == AST_ADDRESS_OF || ast_get_node_type(node) == AST_INDIRECTION || ast_get_node_type(node) == AST_SIZEOF || ast_get_node_type(node) == AST_PRE_INC || ast_get_node_type(node) == AST_PRE_DEC || ast_get_node_type(node) == AST_CAST); + ast_node_t **data = ast_get_data(node); + return data[0]; +} + +ast_node_t *ast_get_cast_type(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CAST); + ast_node_t **data = ast_get_data(node); + return data[0]; +} + +ast_node_t *ast_get_cast_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CAST); + ast_node_t **data = ast_get_data(node); + return data[1]; +} + +--- + +@s + +--- Implementation - Nodes (Binary/Assign/Comma) +struct ast_binary_node { + ast_node_t *left; + ast_node_t *right; +}; + +// Macro to generate binary AST node creation functions +#define AST_CREATE_BINARY_NODE(NODE_TYPE, NODE_NAME) \ +ast_node_t *ast_create_##NODE_NAME##_node(ast_node_t *left, ast_node_t *right, int line, int column) \ +{ \ + ast_node_t *node = ast_create_node(NODE_TYPE, line, column, sizeof(struct ast_binary_node)); \ + struct ast_binary_node *data = ast_get_data(node); \ + data->left = left; \ + data->right = right; \ + return node; \ +} + +AST_CREATE_BINARY_NODE(AST_MUL, mul) +AST_CREATE_BINARY_NODE(AST_DIV, div) +AST_CREATE_BINARY_NODE(AST_MOD, mod) +AST_CREATE_BINARY_NODE(AST_ADD, add) +AST_CREATE_BINARY_NODE(AST_SUB, sub) +AST_CREATE_BINARY_NODE(AST_LEFT_SHIFT, left_shift) +AST_CREATE_BINARY_NODE(AST_RIGHT_SHIFT, right_shift) +AST_CREATE_BINARY_NODE(AST_LESS_THAN, less_than) +AST_CREATE_BINARY_NODE(AST_GREATER_THAN, greater_than) +AST_CREATE_BINARY_NODE(AST_LESS_THAN_OR_EQUAL, less_than_or_equal) +AST_CREATE_BINARY_NODE(AST_GREATER_THAN_OR_EQUAL, greater_than_or_equal) +AST_CREATE_BINARY_NODE(AST_EQUAL, equal) +AST_CREATE_BINARY_NODE(AST_NOT_EQUAL, not_equal) +AST_CREATE_BINARY_NODE(AST_BITWISE_AND, bitwise_and) +AST_CREATE_BINARY_NODE(AST_BITWISE_XOR, bitwise_xor) +AST_CREATE_BINARY_NODE(AST_BITWISE_OR, bitwise_or) +AST_CREATE_BINARY_NODE(AST_LOGICAL_AND, logical_and) +AST_CREATE_BINARY_NODE(AST_LOGICAL_OR, logical_or) +AST_CREATE_BINARY_NODE(AST_ASSIGN, assign) +AST_CREATE_BINARY_NODE(AST_ADD_ASSIGN, add_assign) +AST_CREATE_BINARY_NODE(AST_SUB_ASSIGN, sub_assign) +AST_CREATE_BINARY_NODE(AST_MUL_ASSIGN, mul_assign) +AST_CREATE_BINARY_NODE(AST_DIV_ASSIGN, div_assign) +AST_CREATE_BINARY_NODE(AST_MOD_ASSIGN, mod_assign) +AST_CREATE_BINARY_NODE(AST_LEFT_SHIFT_ASSIGN, left_shift_assign) +AST_CREATE_BINARY_NODE(AST_RIGHT_SHIFT_ASSIGN, right_shift_assign) +AST_CREATE_BINARY_NODE(AST_AND_ASSIGN, bitwise_and_assign) +AST_CREATE_BINARY_NODE(AST_XOR_ASSIGN, bitwise_xor_assign) +AST_CREATE_BINARY_NODE(AST_OR_ASSIGN, bitwise_or_assign) +AST_CREATE_BINARY_NODE(AST_COMMA, comma) + +ast_node_t *ast_get_left_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_MUL || ast_get_node_type(node) == AST_DIV || ast_get_node_type(node) == AST_MOD + || ast_get_node_type(node) == AST_ADD || ast_get_node_type(node) == AST_SUB || ast_get_node_type(node) == AST_LEFT_SHIFT + || ast_get_node_type(node) == AST_RIGHT_SHIFT || ast_get_node_type(node) == AST_LESS_THAN || ast_get_node_type(node) == AST_GREATER_THAN + || ast_get_node_type(node) == AST_LESS_THAN_OR_EQUAL || ast_get_node_type(node) == AST_GREATER_THAN_OR_EQUAL + || ast_get_node_type(node) == AST_EQUAL || ast_get_node_type(node) == AST_NOT_EQUAL + || ast_get_node_type(node) == AST_BITWISE_AND || ast_get_node_type(node) == AST_BITWISE_XOR || ast_get_node_type(node) == AST_BITWISE_OR + || ast_get_node_type(node) == AST_LOGICAL_AND || ast_get_node_type(node) == AST_LOGICAL_OR || ast_get_node_type(node) == AST_ASSIGN + || ast_get_node_type(node) == AST_ADD_ASSIGN || ast_get_node_type(node) == AST_SUB_ASSIGN || ast_get_node_type(node) == AST_MUL_ASSIGN || ast_get_node_type(node) == AST_DIV_ASSIGN + || ast_get_node_type(node) == AST_MOD_ASSIGN || ast_get_node_type(node) == AST_LEFT_SHIFT_ASSIGN || ast_get_node_type(node) == AST_RIGHT_SHIFT_ASSIGN || ast_get_node_type(node) == AST_AND_ASSIGN + || ast_get_node_type(node) == AST_XOR_ASSIGN || ast_get_node_type(node) == AST_OR_ASSIGN || ast_get_node_type(node) == AST_COMMA); + struct ast_binary_node *data = ast_get_data(node); + return data->left; +} + +ast_node_t *ast_get_right_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_MUL || ast_get_node_type(node) == AST_DIV || ast_get_node_type(node) == AST_MOD + || ast_get_node_type(node) == AST_ADD || ast_get_node_type(node) == AST_SUB || ast_get_node_type(node) == AST_LEFT_SHIFT + || ast_get_node_type(node) == AST_RIGHT_SHIFT || ast_get_node_type(node) == AST_LESS_THAN || ast_get_node_type(node) == AST_GREATER_THAN + || ast_get_node_type(node) == AST_LESS_THAN_OR_EQUAL || ast_get_node_type(node) == AST_GREATER_THAN_OR_EQUAL + || ast_get_node_type(node) == AST_EQUAL || ast_get_node_type(node) == AST_NOT_EQUAL + || ast_get_node_type(node) == AST_BITWISE_AND || ast_get_node_type(node) == AST_BITWISE_XOR || ast_get_node_type(node) == AST_BITWISE_OR + || ast_get_node_type(node) == AST_LOGICAL_AND || ast_get_node_type(node) == AST_LOGICAL_OR || ast_get_node_type(node) == AST_ASSIGN + || ast_get_node_type(node) == AST_ADD_ASSIGN || ast_get_node_type(node) == AST_SUB_ASSIGN || ast_get_node_type(node) == AST_MUL_ASSIGN || ast_get_node_type(node) == AST_DIV_ASSIGN + || ast_get_node_type(node) == AST_MOD_ASSIGN || ast_get_node_type(node) == AST_LEFT_SHIFT_ASSIGN || ast_get_node_type(node) == AST_RIGHT_SHIFT_ASSIGN || ast_get_node_type(node) == AST_AND_ASSIGN + || ast_get_node_type(node) == AST_XOR_ASSIGN || ast_get_node_type(node) == AST_OR_ASSIGN || ast_get_node_type(node) == AST_COMMA); + struct ast_binary_node *data = ast_get_data(node); + return data->right; +} + +--- + +@s + +--- Implementation - Nodes (Conditional) +struct ast_conditional_node { + ast_node_t *condition; + ast_node_t *true_expr; + ast_node_t *false_expr; +}; + +ast_node_t *ast_create_conditional_node(ast_node_t *condition, ast_node_t *true_expr, ast_node_t *false_expr, int line, int column) +{ + ast_node_t *node = ast_create_node(AST_CONDITIONAL, line, column, sizeof(struct ast_conditional_node)); + struct ast_conditional_node *data = ast_get_data(node); + data->condition = condition; + data->true_expr = true_expr; + data->false_expr = false_expr; + return node; +} + +ast_node_t *ast_get_conditional_condition(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CONDITIONAL); + struct ast_conditional_node *data = ast_get_data(node); + return data->condition; +} + +ast_node_t *ast_get_conditional_true_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CONDITIONAL); + struct ast_conditional_node *data = ast_get_data(node); + return data->true_expr; +} + +ast_node_t *ast_get_conditional_false_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CONDITIONAL); + struct ast_conditional_node *data = ast_get_data(node); + return data->false_expr; +} + +--- + +@s + +--- Implementation - Nodes (Expression Statement Nodes) +struct ast_expression_statement_node { + ast_node_t *expr; +}; + +ast_node_t *ast_create_expression_statement_node(ast_node_t *expr) +{ + ast_node_t *node = ast_create_node(AST_EXPRESSION_STATEMENT, expr->line, expr->column, sizeof(struct ast_expression_statement_node)); + struct ast_expression_statement_node *data = ast_get_data(node); + data->expr = expr; + return node; +} + +ast_node_t *ast_get_expression_statement_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_EXPRESSION_STATEMENT); + struct ast_expression_statement_node *data = ast_get_data(node); + return data->expr; +} + +--- + +@s + +--- Implementation - Nodes (Label/Case Statement Nodes) +struct ast_label_statement_node { + char *label; +}; + +ast_node_t *ast_create_label_statement_node(char *label, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_LABEL_STATEMENT, line, col, sizeof(struct ast_label_statement_node)); + struct ast_label_statement_node *data = ast_get_data(node); + data->label = label; + return node; +} + +char *ast_get_label_statement_label(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_LABEL_STATEMENT); + struct ast_label_statement_node *data = ast_get_data(node); + return data->label; +} + +ast_node_t *ast_create_case_statement_node(ast_node_t *expr, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_CASE_STATEMENT, line, col, sizeof(ast_node_t *)); + ast_node_t **data = ast_get_data(node); + *data = expr; + return node; +} + +ast_node_t *ast_get_case_statement_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_CASE_STATEMENT); + ast_node_t **data = ast_get_data(node); + return *data; +} + +ast_node_t *ast_create_default_statement_node(int line, int col) +{ + return ast_create_node(AST_DEFAULT_STATEMENT, line, col, 0); +} +--- + +@s + +--- Implementation - Nodes (Compound Statement Nodes) +struct ast_compound_statement_node { + ast_node_t **decls_and_stmts; + size_t num_decls_and_stmts; +}; + +ast_node_t *ast_create_compound_statement_node(ast_node_t **decls_and_stmts, size_t num_decls_and_stmts, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_COMPOUND_STATEMENT, line, col, sizeof(struct ast_compound_statement_node)); + struct ast_compound_statement_node *data = ast_get_data(node); + data->decls_and_stmts = decls_and_stmts; + data->num_decls_and_stmts = num_decls_and_stmts; + return node; +} + +ast_node_t **ast_get_compound_statement_contents(ast_node_t *node, size_t *num_contents) +{ + assert(ast_get_node_type(node) == AST_COMPOUND_STATEMENT); + struct ast_compound_statement_node *data = ast_get_data(node); + *num_contents = data->num_decls_and_stmts; + return data->decls_and_stmts; +} + +--- + +@s + +--- Implementation - Nodes (Conditional Statement Nodes) +struct ast_if_statement_node { + ast_node_t *condition; + ast_node_t *true_stmt; + ast_node_t *false_stmt; +}; + +ast_node_t *ast_create_if_statement_node(ast_node_t *condition, ast_node_t *true_stmt, ast_node_t *false_stmt, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_IF_STATEMENT, line, col, sizeof(struct ast_if_statement_node)); + struct ast_if_statement_node *data = ast_get_data(node); + data->condition = condition; + data->true_stmt = true_stmt; + data->false_stmt = false_stmt; + return node; +} + +ast_node_t *ast_get_if_statement_condition(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_IF_STATEMENT); + struct ast_if_statement_node *data = ast_get_data(node); + return data->condition; +} + +ast_node_t *ast_get_if_statement_true_stmt(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_IF_STATEMENT); + struct ast_if_statement_node *data = ast_get_data(node); + return data->true_stmt; +} + +ast_node_t *ast_get_if_statement_false_stmt(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_IF_STATEMENT); + struct ast_if_statement_node *data = ast_get_data(node); + return data->false_stmt; +} + +--- + +@s + +--- Implementation - Nodes (Iteration Statement Nodes) + +struct ast_iteration_statement_node { + ast_node_t *condition; + ast_node_t *stmt; +}; + +ast_node_t *ast_create_while_statement_node(ast_node_t *condition, ast_node_t *stmt, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_WHILE_STATEMENT, line, col, sizeof(struct ast_iteration_statement_node)); + struct ast_iteration_statement_node *data = ast_get_data(node); + data->condition = condition; + data->stmt = stmt; + return node; +} + +ast_node_t *ast_create_do_while_statement_node(ast_node_t *condition, ast_node_t *stmt, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_DO_WHILE_STATEMENT, line, col, sizeof(struct ast_iteration_statement_node)); + struct ast_iteration_statement_node *data = ast_get_data(node); + data->condition = condition; + data->stmt = stmt; + return node; +} + +// Shares the first two members with ast_iteration_statement_node +struct ast_for_statement_node { + ast_node_t *condition; + ast_node_t *stmt; + ast_node_t *init; + ast_node_t *update; + +}; + +ast_node_t *ast_create_for_statement_node(ast_node_t *init, ast_node_t *condition, ast_node_t *update, ast_node_t *stmt, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_FOR_STATEMENT, line, col, sizeof(struct ast_for_statement_node)); + struct ast_for_statement_node *data = ast_get_data(node); + data->init = init; + data->condition = condition; + data->update = update; + data->stmt = stmt; + return node; +} + +ast_node_t *ast_get_iteration_statement_condition(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_WHILE_STATEMENT || ast_get_node_type(node) == AST_DO_WHILE_STATEMENT || ast_get_node_type(node) == AST_FOR_STATEMENT); + struct ast_iteration_statement_node *data = ast_get_data(node); + return data->condition; +} + +ast_node_t *ast_get_iteration_statement_stmt(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_WHILE_STATEMENT || ast_get_node_type(node) == AST_DO_WHILE_STATEMENT || ast_get_node_type(node) == AST_FOR_STATEMENT); + struct ast_iteration_statement_node *data = ast_get_data(node); + return data->stmt; +} + +ast_node_t *ast_get_for_statement_init(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_FOR_STATEMENT); + struct ast_for_statement_node *data = ast_get_data(node); + return data->init; +} + +ast_node_t *ast_get_for_statement_update(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_FOR_STATEMENT); + struct ast_for_statement_node *data = ast_get_data(node); + return data->update; +} +--- + +@s + +--- Implementation - Nodes (Jump Statement Nodes) +struct ast_goto_statement_node { + char *label; +}; + +ast_node_t *ast_create_goto_statement_node(char *label, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_GOTO_STATEMENT, line, col, sizeof(struct ast_goto_statement_node)); + struct ast_goto_statement_node *data = ast_get_data(node); + data->label = label; + return node; +} + +char *ast_get_goto_statement_label(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_GOTO_STATEMENT); + struct ast_goto_statement_node *data = ast_get_data(node); + return data->label; +} + +ast_node_t *ast_create_continue_statement_node(int line, int col) +{ + return ast_create_node(AST_CONTINUE_STATEMENT, line, col, 0); +} + +ast_node_t *ast_create_break_statement_node(int line, int col) +{ + return ast_create_node(AST_BREAK_STATEMENT, line, col, 0); +} + +ast_node_t *ast_create_return_statement_node(ast_node_t *expr, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_RETURN_STATEMENT, line, col, sizeof(ast_node_t *)); + ast_node_t **data = ast_get_data(node); + *data = expr; + return node; +} + +ast_node_t *ast_get_return_statement_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_RETURN_STATEMENT); + ast_node_t **data = ast_get_data(node); + return *data; +} + +--- + +@s + +--- Implementation - Nodes (Switch Statement Nodes) + +struct ast_switch_statement_node { + ast_node_t *expr; + ast_node_t *stmt; +}; + +ast_node_t *ast_create_switch_statement_node(ast_node_t *expr, ast_node_t *stmt, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_SWITCH_STATEMENT, line, col, sizeof(struct ast_switch_statement_node)); + struct ast_switch_statement_node *data = ast_get_data(node); + data->expr = expr; + data->stmt = stmt; + return node; +} + +ast_node_t *ast_get_switch_statement_expr(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_SWITCH_STATEMENT); + struct ast_switch_statement_node *data = ast_get_data(node); + return data->expr; +} + +ast_node_t *ast_get_switch_statement_stmt(ast_node_t *node) +{ + assert(ast_get_node_type(node) == AST_SWITCH_STATEMENT); + struct ast_switch_statement_node *data = ast_get_data(node); + return data->stmt; +} +--- + +--- Implementation - Nodes (Simple Declaration Nodes) +struct var_decl_data { + ast_node_t *type; + char *id; +}; + +ast_node_t *ast_create_var_decl_node(ast_node_t *type, char *id, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_VAR_DECL, line, col, sizeof(struct var_decl_data)); + struct var_decl_data *data = ast_get_data(node); + data->type = type; + data->id = id; + return (ast_node_t *)data; +} + +ast_node_t *ast_get_var_decl_type(ast_node_t *node) +{ + struct var_decl_data *data = ast_get_data(node); + return data->type; +} + +char *ast_get_var_decl_id(ast_node_t *node) +{ + struct var_decl_data *data = ast_get_data(node); + return data->id; +} + +struct fun_decl_data { + ast_node_t *type; + char *id; + ast_node_t **params; + size_t num_params; +}; + +ast_node_t *ast_create_fun_decl_node(ast_node_t *type, char *id, ast_node_t **params, size_t num_params, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_FUN_DECL, line, col, sizeof(struct fun_decl_data)); + struct fun_decl_data *data = ast_get_data(node); + data->type = type; + data->id = id; + data->params = params; + data->num_params = num_params; + return (ast_node_t *)data; +} + +ast_node_t *ast_get_fun_decl_type(ast_node_t *node) +{ + struct fun_decl_data *data = ast_get_data(node); + return data->type; +} + +char *ast_get_fun_decl_id(ast_node_t *node) +{ + struct fun_decl_data *data = ast_get_data(node); + return data->id; +} + +ast_node_t **ast_get_fun_decl_params(ast_node_t *node, size_t *num_params) +{ + struct fun_decl_data *data = ast_get_data(node); + *num_params = data->num_params; + return data->params; +} + +--- + +@s + +--- Implementation - Nodes (Parameter Declaration Nodes) +struct param_data { + ast_node_t *type; + char *id; +}; + +ast_node_t *ast_create_param_node(ast_node_t *type, char *id, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_PARAM, line, col, sizeof(struct param_data)); + struct param_data *data = ast_get_data(node); + data->type = type; + data->id = id; + return node; +} + +ast_node_t *ast_get_param_type(ast_node_t *node) +{ + struct param_data *data = ast_get_data(node); + return data->type; +} + +char *ast_get_param_id(ast_node_t *node) +{ + struct param_data *data = ast_get_data(node); + return data->id; +} + +--- + +@s + +--- Implementation - Nodes (Function Definition Nodes) + +struct fun_def_data { + ast_node_t *type; + char *id; + ast_node_t **params; + size_t num_params; + ast_node_t *stmt; +}; + +ast_node_t *ast_create_fun_def_node(ast_node_t *type, char *id, ast_node_t **params, size_t num_params, ast_node_t *stmt, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_FUN_DEF, line, col, sizeof(struct fun_def_data)); + struct fun_def_data *data = ast_get_data(node); + data->type = type; + data->id = id; + data->params = params; + data->num_params = num_params; + data->stmt = stmt; + return node; +} + +ast_node_t *ast_get_fun_def_type(ast_node_t *node) +{ + struct fun_def_data *data = ast_get_data(node); + return data->type; +} + +char *ast_get_fun_def_id(ast_node_t *node) +{ + struct fun_def_data *data = ast_get_data(node); + return data->id; +} + +ast_node_t **ast_get_fun_def_params(ast_node_t *node, size_t *num_params) +{ + struct fun_def_data *data = ast_get_data(node); + *num_params = data->num_params; + return data->params; +} + +ast_node_t *ast_get_fun_def_stmt(ast_node_t *node) +{ + struct fun_def_data *data = ast_get_data(node); + return data->stmt; +} + +--- + +@s + +--- Implementation - Nodes (Struct Declaration Nodes) +struct struct_decl_data { + char *id; + ast_node_t **members; + size_t num_members; +}; + +ast_node_t *ast_create_struct_decl_node(char *id, ast_node_t **members, size_t num_members, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_STRUCT_DECL, line, col, sizeof(struct struct_decl_data)); + struct struct_decl_data *data = ast_get_data(node); + data->id = id; + data->members = members; + data->num_members = num_members; + return node; +} + +char *ast_get_struct_decl_id(ast_node_t *node) +{ + struct struct_decl_data *data = ast_get_data(node); + return data->id; +} + +ast_node_t **ast_get_struct_decl_members(ast_node_t *node, size_t *num_members) +{ + struct struct_decl_data *data = ast_get_data(node); + *num_members = data->num_members; + return data->members; +} +--- + +@s + +--- Implementation - Nodes (Union Declaration Nodes) +struct union_decl_data { + char *id; + ast_node_t **members; + size_t num_members; +}; + +ast_node_t *ast_create_union_decl_node(char *id, ast_node_t **members, size_t num_members, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_UNION_DECL, line, col, sizeof(struct union_decl_data)); + struct union_decl_data *data = ast_get_data(node); + data->id = id; + data->members = members; + data->num_members = num_members; + return node; +} + +char *ast_get_union_decl_id(ast_node_t *node) +{ + struct union_decl_data *data = ast_get_data(node); + return data->id; +} + +ast_node_t **ast_get_union_decl_members(ast_node_t *node, size_t *num_members) +{ + struct union_decl_data *data = ast_get_data(node); + *num_members = data->num_members; + return data->members; +} + +--- + +@s + +--- Implementation - Nodes (Enum Declaration Nodes) +struct enum_decl_data { + char *id; + ast_node_t **enums; + size_t num_enums; +}; + +ast_node_t *ast_create_enum_decl_node(char *id, ast_node_t **enums, size_t num_enums, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_ENUM_DECL, line, col, sizeof(struct enum_decl_data)); + struct enum_decl_data *data = ast_get_data(node); + data->id = id; + data->enums = enums; + data->num_enums = num_enums; + return node; +} + +char *ast_get_enum_decl_id(ast_node_t *node) +{ + struct enum_decl_data *data = ast_get_data(node); + return data->id; +} + +ast_node_t **ast_get_enum_decl_enums(ast_node_t *node, size_t *num_enums) +{ + struct enum_decl_data *data = ast_get_data(node); + *num_enums = data->num_enums; + return data->enums; +} + +--- + +@s + +--- Implementation - Nodes (Typedef Declaration Nodes) +struct typedef_data { + ast_node_t *type; + char *id; +}; + +ast_node_t *ast_create_typedef_node(ast_node_t *type, char *id, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_TYPEDEF, line, col, sizeof(struct typedef_data)); + struct typedef_data *data = ast_get_data(node); + data->type = type; + data->id = id; + return node; +} + +ast_node_t *ast_get_typedef_type(ast_node_t *node) +{ + struct typedef_data *data = ast_get_data(node); + return data->type; +} + +char *ast_get_typedef_id(ast_node_t *node) +{ + struct typedef_data *data = ast_get_data(node); + return data->id; +} + +--- + +@s + +--- Implementation - Nodes (Types/Members) +struct type_data { + token_t **type; + size_t num_type; +}; + +ast_node_t *ast_create_type_node(token_t *type[], size_t num_type, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_TYPE, line, col, sizeof(struct type_data)); + struct type_data *data = ast_get_data(node); + data->type = type; + data->num_type = num_type; + return node; +} + +token_t **ast_get_type(ast_node_t *node, size_t *num_type) +{ + struct type_data *data = ast_get_data(node); + *num_type = data->num_type; + return data->type; +} + +struct member_data { + ast_node_t *type; + char *id; +}; + +ast_node_t *ast_create_member_node(ast_node_t *type, char *id, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_MEMBER, line, col, sizeof(struct member_data)); + struct member_data *data = ast_get_data(node); + data->type = type; + data->id = id; + return node; +} + +ast_node_t *ast_get_member_type(ast_node_t *node) +{ + struct member_data *data = ast_get_data(node); + return data->type; +} + +char *ast_get_member_id(ast_node_t *node) +{ + struct member_data *data = ast_get_data(node); + return data->id; +} + +struct enum_member_data { + char *id; + ast_node_t *value; +}; + +ast_node_t *ast_create_enum_member_node(char *id, ast_node_t *value, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_ENUM_MEMBER, line, col, sizeof(struct enum_member_data)); + struct enum_member_data *data = ast_get_data(node); + data->id = id; + data->value = value; + return node; +} + +char *ast_get_enum_member_id(ast_node_t *node) +{ + struct enum_member_data *data = ast_get_data(node); + return data->id; +} + +ast_node_t *ast_get_enum_member_expr(ast_node_t *node) +{ + struct enum_member_data *data = ast_get_data(node); + return data->value; +} + +--- + +@s + +--- Implementation - Nodes (Translation Unit Nodes) +struct translation_unit_data { + ast_node_t **items; + size_t num_items; +}; + +ast_node_t *ast_create_translation_unit_node(ast_node_t **items, size_t num_items, int line, int col) +{ + ast_node_t *node = ast_create_node(AST_TRANSLATION_UNIT, line, col, sizeof(struct translation_unit_data)); + struct translation_unit_data *data = ast_get_data(node); + data->items = items; + data->num_items = num_items; + return node; +} + +ast_node_t **ast_get_translation_unit_items(ast_node_t *node, size_t *num_items) +{ + struct translation_unit_data *data = ast_get_data(node); + *num_items = data->num_items; + return data->items; +} +--- + +@s +Freeing the AST is going to be pretty painful. We need to free all the nodes, and all the data associated with them. We'll start by freeing the data associated with each node, and then free the node itself. We'll do this recursively, so that we can free all the nodes in the tree. +--- Implementation - Nodes (Freeing) +void ast_free_node(ast_node_t *node) { + if (!node) { + return; + } + switch (ast_get_node_type(node)) { + case AST_INTU32: + case AST_INTU64: + case AST_INTS32: + case AST_INTS64: + case AST_FLOAT: + case AST_DOUBLE: + case AST_STRING: + case AST_CHAR: + case AST_VAR: + break; + case AST_SUBSCRIPT: + ast_free_node(ast_get_subscript_expr(node)); + ast_free_node(ast_get_subscript_idx(node)); + free(node); + break; + case AST_DIRECT_COMPONENT_SELECTION: + case AST_INDIRECT_COMPONENT_SELECTION: + ast_free_node(ast_get_component_expr(node)); + free(node); + break; + case AST_FUNCTION_CALL: { + size_t num_args; + ast_node_t **args = ast_get_function_call_args(node, &num_args); + for (size_t i = 0; i < num_args; i++) { + ast_free_node(args[i]); + } + free(args); + ast_free_node(ast_get_function_call_expr(node)); + free(node); + break; + } + case AST_POSTFIX_INC: + case AST_POSTFIX_DEC: { + ast_free_node(ast_get_postfix_expr(node)); + free(node); + break; + } + case AST_UNARY_PLUS: + case AST_UNARY_MINUS: + case AST_LOGICAL_NOT: + case AST_BITWISE_NOT: + case AST_ADDRESS_OF: + case AST_INDIRECTION: + case AST_SIZEOF: + case AST_PRE_INC: + case AST_PRE_DEC: { + ast_free_node(ast_get_unary_expr(node)); + free(node); + break; + } + case AST_CAST: { + ast_free_node(ast_get_cast_type(node)); + ast_free_node(ast_get_cast_expr(node)); + free(node); + break; + } + case AST_MUL: + case AST_DIV: + case AST_MOD: + case AST_ADD: + case AST_SUB: + case AST_LEFT_SHIFT: + case AST_RIGHT_SHIFT: + case AST_LESS_THAN: + case AST_GREATER_THAN: + case AST_LESS_THAN_OR_EQUAL: + case AST_GREATER_THAN_OR_EQUAL: + case AST_EQUAL: + case AST_NOT_EQUAL: + case AST_BITWISE_AND: + case AST_BITWISE_XOR: + case AST_BITWISE_OR: + case AST_LOGICAL_AND: + case AST_LOGICAL_OR: + case AST_COMMA: + case AST_ASSIGN: + case AST_ADD_ASSIGN: + case AST_SUB_ASSIGN: + case AST_MUL_ASSIGN: + case AST_DIV_ASSIGN: + case AST_MOD_ASSIGN: + case AST_LEFT_SHIFT_ASSIGN: + case AST_RIGHT_SHIFT_ASSIGN: + case AST_AND_ASSIGN: + case AST_XOR_ASSIGN: + case AST_OR_ASSIGN: + { + ast_free_node(ast_get_left_expr(node)); + ast_free_node(ast_get_right_expr(node)); + free(node); + break; + } + case AST_CONDITIONAL: { + ast_free_node(ast_get_conditional_condition(node)); + ast_free_node(ast_get_conditional_true_expr(node)); + ast_free_node(ast_get_conditional_false_expr(node)); + free(node); + break; + } + case AST_EXPRESSION_STATEMENT: + ast_free_node(ast_get_expression_statement_expr(node)); + free(node); + break; + case AST_LABEL_STATEMENT: + free(node); + break; + case AST_CASE_STATEMENT: + ast_free_node(ast_get_case_statement_expr(node)); + free(node); + break; + case AST_DEFAULT_STATEMENT: + free(node); + break; + case AST_COMPOUND_STATEMENT: + { + size_t size = 0; + ast_node_t **comp_stmts = ast_get_compound_statement_contents(node, &size); + for(size_t i = 0; i < size; i++) + { + ast_free_node(comp_stmts[i]); + } + free(comp_stmts); + free(node); + break; + } + case AST_IF_STATEMENT: + { + ast_free_node(ast_get_if_statement_condition(node)); + ast_free_node(ast_get_if_statement_true_stmt(node)); + ast_free_node(ast_get_if_statement_false_stmt(node)); + free(node); + break; + } + case AST_WHILE_STATEMENT: + case AST_DO_WHILE_STATEMENT: + { + ast_free_node(ast_get_iteration_statement_condition(node)); + ast_free_node(ast_get_iteration_statement_stmt(node)); + free(node); + break; + } + case AST_FOR_STATEMENT: + { + ast_free_node(ast_get_for_statement_init(node)); + ast_free_node(ast_get_iteration_statement_condition(node)); + ast_free_node(ast_get_for_statement_update(node)); + ast_free_node(ast_get_iteration_statement_stmt(node)); + free(node); + break; + } + case AST_GOTO_STATEMENT: + free(node); + break; + case AST_CONTINUE_STATEMENT: + case AST_BREAK_STATEMENT: + free(node); + break; + case AST_RETURN_STATEMENT: + ast_free_node(ast_get_return_statement_expr(node)); + free(node); + break; + case AST_SWITCH_STATEMENT: + { + ast_free_node(ast_get_switch_statement_expr(node)); + ast_free_node(ast_get_switch_statement_stmt(node)); + free(node); + break; + } + case AST_NULL_STATEMENT: + free(node); + break; + case AST_VAR_DECL: + { + ast_node_t *type = ast_get_var_decl_type(node); + ast_free_node(type); + free(node); + break; + } + case AST_FUN_DECL: + { + ast_node_t *type = ast_get_fun_decl_type(node); + ast_free_node(type); + size_t num_params; + ast_node_t **params = ast_get_fun_decl_params(node, &num_params); + for(size_t i = 0; i < num_params; i++) + { + ast_free_node(params[i]); + } + free(params); + free(node); + break; + } + case AST_PARAM: + { + ast_node_t *type = ast_get_param_type(node); + ast_free_node(type); + free(node); + break; + } + case AST_FUN_DEF: + { + ast_node_t *type = ast_get_fun_def_type(node); + ast_free_node(type); + size_t num_params; + ast_node_t **params = ast_get_fun_def_params(node, &num_params); + for(size_t i = 0; i < num_params; i++) + { + ast_free_node(params[i]); + } + free(params); + ast_free_node(ast_get_fun_def_stmt(node)); + free(node); + break; + } + case AST_STRUCT_DECL: + { + size_t num_members; + ast_node_t **members = ast_get_struct_decl_members(node, &num_members); + for(size_t i = 0; i < num_members; i++) + { + ast_free_node(members[i]); + } + free(members); + free(node); + break; + } + case AST_UNION_DECL: + { + size_t num_members; + ast_node_t **members = ast_get_union_decl_members(node, &num_members); + for(size_t i = 0; i < num_members; i++) + { + ast_free_node(members[i]); + } + free(members); + free(node); + break; + } + case AST_ENUM_DECL: + { + size_t num_enums; + ast_node_t **enums = ast_get_enum_decl_enums(node, &num_enums); + for(size_t i = 0; i < num_enums; i++) + { + ast_free_node(enums[i]); + } + free(enums); + free(node); + break; + } + case AST_TYPEDEF: + { + ast_node_t *type = ast_get_typedef_type(node); + ast_free_node(type); + free(node); + break; + } + case AST_TYPE: + { + token_t **type; + size_t num_type; + type = ast_get_type(node, &num_type); + for(size_t i = 0; i < num_type; i++) + { + free(type[i]); + } + free(type); + free(node); + break; + } + case AST_MEMBER: + { + ast_node_t *type = ast_get_member_type(node); + ast_free_node(type); + free(node); + break; + } + case AST_ENUM_MEMBER: + { + ast_node_t *value = ast_get_enum_member_expr(node); + ast_free_node(value); + free(node); + break; + } + case AST_TRANSLATION_UNIT: + { + size_t num_items; + ast_node_t **items = ast_get_translation_unit_items(node, &num_items); + for(size_t i = 0; i < num_items; i++) + { + ast_free_node(items[i]); + } + free(items); + free(node); + break; + } + default: + assert(0); + } + +} +--- + +@s +--- ast.c +#include <stdlib.h> +#include <assert.h> +#include "ast.h" +@{Implementation - Common Node Structure} +@{Implementation - Nodes (Primary)} +@{Implementation - Nodes (Postfix)} +@{Implementation - Nodes (Unary/Cast)} +@{Implementation - Nodes (Binary/Assign/Comma)} +@{Implementation - Nodes (Conditional)} +@{Implementation - Nodes (Expression Statement Nodes)} +@{Implementation - Nodes (Label/Case Statement Nodes)} +@{Implementation - Nodes (Compound Statement Nodes)} +@{Implementation - Nodes (Conditional Statement Nodes)} +@{Implementation - Nodes (Iteration Statement Nodes)} +@{Implementation - Nodes (Jump Statement Nodes)} +@{Implementation - Nodes (Switch Statement Nodes)} +@{Implementation - Nodes (Simple Declaration Nodes)} +@{Implementation - Nodes (Parameter Declaration Nodes)} +@{Implementation - Nodes (Function Definition Nodes)} +@{Implementation - Nodes (Struct Declaration Nodes)} +@{Implementation - Nodes (Union Declaration Nodes)} +@{Implementation - Nodes (Enum Declaration Nodes)} +@{Implementation - Nodes (Typedef Declaration Nodes)} +@{Implementation - Nodes (Types/Members)} +@{Implementation - Nodes (Translation Unit Nodes)} +@{Implementation - Nodes (Freeing)} +---+ \ No newline at end of file diff --git a/projects/cminus/code/lexer.lit b/projects/cminus/code/lexer.lit @@ -1,6 +1,6 @@ @code_type c .c @comment_type /* %s */ -@compiler lit -t lexer.lit && gcc -Wall -Wextra -Wstrict-aliasing=3 -Wwrite-strings -Wvla -Wcast-align=strict -Wstrict-prototypes -Wstringop-overflow=4 -Wshadow -fanalyzer tokenizer.c input.c hash_table.c token.c -D TEST_TOKENIZER -g -O0 -o lextest && valgrind --leak-check=full ./lextest tokenizer.c && rm lextest +@compiler lit -t lexer.lit && gcc -Wall -Wextra -Wstrict-aliasing=3 -Wwrite-strings -Wvla -Wcast-align=strict -Wstrict-prototypes -Wstringop-overflow=4 -Wshadow -fanalyzer tokenizer.c input.c hash_table.c token.c util.c -D TEST_TOKENIZER -g -O0 -o lextest && valgrind --leak-check=full ./lextest tokenizer.c && rm lextest @title Lexer @add_css ./style.css @@ -11,8 +11,7 @@ The project has a series of pretty typical stages: 1. The lexer. This takes a file as input and emits a series of tokens (Its input is already preprocessed, I outsource that to "gcc -E"). 2. The parser. This takes the tokens and builds an abstract syntax tree (AST). -3. The symbol table. This exists in a sort of in-between space next to the lexer and parser. It's used to store information about variables and functions. -4. The type checker. This is used to ensure that the types of variables and functions are correct. +4. The type checker/semantic analyzer. This is used to ensure that the types of variables and functions are correct. 5. The code generator. This takes the AST and generates an intermediate representation (IR). 6. The optimizer. This takes the IR and optimizes it. This'll be broken up into a few stages. 7. The lowerer. This takes the IR and lowers it to a simpler IR. @@ -216,6 +215,7 @@ typedef enum { // Identifiers TOK_ID, + TOK_TYPEDEF_NAME, // Constants TOK_INTEGER_U32, // u @@ -310,7 +310,7 @@ double token_float(token_t *token) { } const char *token_string(token_t *token) { - assert(token->kind == TOK_STRING_ASCII || token->kind == TOK_ID); + assert(token->kind == TOK_STRING_ASCII || token->kind == TOK_ID || token->kind == TOK_TYPEDEF_NAME); assert(token->magic == TOK_MAGIC_1); return token_data(token)->data.s; } @@ -487,6 +487,8 @@ const char *token_name_from_type(c_token_types type) { return "TOK_HASH"; case TOK_ID: return "TOK_ID"; + case TOK_TYPEDEF_NAME: + return "TOK_TYPEDEF_NAME"; case TOK_INTEGER_U32: return "TOK_INTEGER_U32"; case TOK_INTEGER_U64: @@ -591,6 +593,12 @@ void print_token(token_t *tok) { free(escaped); break; } + case TOK_TYPEDEF_NAME: { + char *escaped = re_escape_string(token_string(tok)); + printf("%s: %s@%d:%d\n", name, escaped, tok->line, tok->column); + free(escaped); + break; + } case TOK_CHAR_CONST: printf("%s: '%c'@%d:%d\n", name, token_char(tok), tok->line, tok->column); break; @@ -961,7 +969,7 @@ Instead of trying to come up with a new hash function, we can use one that's bee The first time I wrote this, I used the hash function from the 'Red Dragon Book' (Compilers: Principles, Techniques, and Tools). --- Hash Function -static unsigned long hash_string(void *key) { +unsigned long hash_string(void *key) { unsigned long hash = 0, g; char *p = key; while (*p) { @@ -978,7 +986,7 @@ This is a bit slow on modern processors because it's not very cache-friendly. We As you can see in the code below, this function avoids extra operations and should be much faster. --- Hash Function := -static unsigned int hash_string(const void *key) { +unsigned int hash_string(const void *key) { unsigned long hash = 0, hi = 0; const char *p = key; hash = *p; @@ -1008,7 +1016,7 @@ static unsigned int hash_string(const void *key) { @s We also need a comparison function for strings. --- String Comparison -static int cmp_string(const void *key1, const void *key2) { +int cmp_string(const void *key1, const void *key2) { return strcmp((char *)key1, (char *)key2); } --- @@ -1016,21 +1024,37 @@ static int cmp_string(const void *key1, const void *key2) { @s Finally, we'll need a destructor for entries. --- String Destructor -static void dtor_string(void *value, int is_key) { +void dtor_string(void *value, int is_key) { if (is_key) { free(value); // Since the key and value are the same, we only need to free once. } } --- +@s +These functions go in util.c +--- util.c +#include <string.h> +#include <stdlib.h> +#include "hash_table.h" +@{String Comparison} +@{Hash Function} +@{String Destructor} +--- +--- util.h +#ifndef UTIL_H +#define UTIL_H +#include "hash_table.h" +int cmp_string(const void *key1, const void *key2); +unsigned int hash_string(const void *key); +void dtor_string(void *value, int is_key); +#endif +--- @s Now we can implement `token_create_string` the right way. You might notice that we're using the same key and value. This way of using a hash table is normally called a set. We're using it to store strings, but we could use it to store anything we want to deduplicate. --- Token Create String --- := -@{String Comparison} -@{Hash Function} -@{String Destructor} hash_table_t *string_table; token_t *token_create_string(c_token_types kind, int lin, int col, const char *s, int len) { @@ -1075,6 +1099,7 @@ Finally, we implement the token data structure in `token.c`. #include <ctype.h> #include "token.h" #include "hash_table.h" +#include "util.h" @{Token Data Structure} @{Token Data Access} @{Token Creation and Destruction} @@ -1231,9 +1256,8 @@ void consume_alt(c_token_types *kinds, int n); --- @s -Now we can finally implement the tokenizer. +Now we can finally implement the tokenizer. A stack for storing tokens for lookahead is defined, as is a hash table, modified by the parser, for typedefs. --- tokenizer.c -#include <assert.h> #include <ctype.h> #include <errno.h> #include <float.h> @@ -1246,8 +1270,10 @@ Now we can finally implement the tokenizer. #include "tokenizer.h" #include "token.h" #include "input.h" +#include "util.h" token_t *left_stack[8]; int left_stack_pos = 0; +hash_table_t *typedef_table = NULL; @{Utility Functions} @{Tokenization Function} --- @@ -1257,6 +1283,7 @@ Utility functions are everything that doesn't directly tokenize the input. --- Utility Functions void init_tokenizer(const char *filename) { input_init(filename); + typedef_table = hash_table_create(16, cmp_string, hash_string, dtor_string); } void destroy_tokenizer(void) { @@ -1451,6 +1478,8 @@ const char *stringify_type(c_token_types type) { return "#"; case TOK_ID: return "identifier"; + case TOK_TYPEDEF_NAME: + return "typedef name"; case TOK_INTEGER_U32: case TOK_INTEGER_U64: case TOK_INTEGER_S32: @@ -1674,6 +1703,10 @@ static token_t *read_identifier(void) { if (kind != TOK_ID) { return token_create(kind, line, column, i); } + // Check if it's a typedef + if (hash_table_get(typedef_table, buf) != NULL) { + return token_create(TOK_TYPEDEF_NAME, line, column, i); + } return token_create_string(kind, line, column, buf, i); } --- diff --git a/projects/cminus/code/makefile b/projects/cminus/code/makefile @@ -2,6 +2,12 @@ all: lit -c lexer.lit lit lexer.lit mv lexer.html .. + lit -c ast.lit + lit ast.lit + mv ast.html .. + lit -c parser.lit + lit parser.lit + mv parser.html .. clean: rm -f *.h diff --git a/projects/cminus/code/parser.lit b/projects/cminus/code/parser.lit @@ -0,0 +1,48 @@ +@code_type c .c +@comment_type /* %s */ +@compiler lit -t parser.lit && gcc -Wall -Wextra -Wstrict-aliasing=3 -Wwrite-strings -Wvla -Wcast-align=strict -Wstrict-prototypes -Wstringop-overflow=4 -Wshadow -fanalyzer -c parser.c -D TEST_PARSER -g -O0 -o parser.o + +@title Parser +@add_css ./style.css +@s Note +THIS IS A LITERATE PROGRAM! Go to [this link](https://reagancfischer.dev/projects/cminus/code/parser.lit) to see the file that generated this HTML. + +@s The Parser +The parser takes tokens from the lexer and builds an abstract syntax tree (AST) which we'll use to generate code. I'll be using a recursive descent parser for this project. + +This will be a "dumb" parser, meaning it won't do any semantic analysis or type checking. You can see this distinction in the code for parsing declarations, which just stores the tokens for the declaration in the type itself instead of building a type. + +A consequence of this is that the parser will freely accept nonsense like `double int x` or `int x = "hello";`, because both are valid according to the (simplified) grammar rules "vardecl -> type ID" and "vardecl -> type ID = expr". + +The parser also won't build a symbol table. That'll be done in the semantic analysis phase. + +@s Design + +I'll break the parser into several modules: +- 'ast.c' will contain functions for building the AST, with similar isolation to the lexer. +- 'parsing.c' will contain functions for supporting the parser. If I define any functions that don't directly implement a grammar rule, they'll go here. +- 'expression.c' will contain functions for parsing expressions. +- 'declaration.c' will contain functions for parsing declarations. +- 'statement.c' will contain functions for parsing statements. + +@s The AST Interface +The AST will be a tree of nodes, each representing a different part of the program. I'll define the AST in 'ast.h' and implement it in 'ast.c'. Like we did for tokens in the lexer, the AST will be an opaque type. The parser will only interact with the AST through functions I provide. + +We'll need functions for creating and destroying nodes and functions for getting the types and values of nodes. I'm going to make the AST immutable, meaning that once a node is created, it can't be changed. + +The AST will be implemented in 'ast.c'. All AST nodes share a common type, but extra data is stored using a zero-length array which resolves to a variable structure. + +All the code for this is about 1500 lines of mind-numbing code. See the full implementation [here](https://reagancfischer.dev/projects/cminus/ast.html). + +@s The Parser Interface + +# Source code, biblography +A lot of the logic for this project is from either the Dragon Book, Engineering a Compiler, or LCC: A Retargetable Compiler for ANSI C. Grammars are from The C Reference Manual. + + +Literate programming rendered using [literate](https://github.com/zyedidia/Literate). + + <footer style=" text-align: center; padding: 20px;"> + <p>© 2024 Reagan Fischer. If for some reason you want to use my AMAZING code (lol), it's available under the MIT + license <a href="/projects/cminus/code/LICENSE.md">here</a>.</p> + </footer>+ \ No newline at end of file diff --git a/projects/cminus/code/token.c b/projects/cminus/code/token.c @@ -6,6 +6,7 @@ #include <ctype.h> #include "token.h" #include "hash_table.h" +#include "util.h" /* Token Data Structure */ #define TOK_MAGIC_1 0x544F4B454E544F4Bul // "TOKENTOK" #define TOK_MAGIC_2 0x544F4B544F4B454Eul // "TOKTOKEN" @@ -54,7 +55,7 @@ double token_float(token_t *token) { } const char *token_string(token_t *token) { - assert(token->kind == TOK_STRING_ASCII || token->kind == TOK_ID); + assert(token->kind == TOK_STRING_ASCII || token->kind == TOK_ID || token->kind == TOK_TYPEDEF_NAME); assert(token->magic == TOK_MAGIC_1); return token_data(token)->data.s; } @@ -132,45 +133,6 @@ void token_destroy(token_t *token) { } /* Token Create String */ -/* String Comparison */ -static int cmp_string(const void *key1, const void *key2) { - return strcmp((char *)key1, (char *)key2); -} - -/* Hash Function */ -static unsigned int hash_string(const void *key) { - unsigned long hash = 0, hi = 0; - const char *p = key; - hash = *p; - if (hash != 0 && p[1] != 0) { - hash = (hash << 4) + p[1]; - if (p[2] != 0) { - hash = (hash << 4) + p[2]; - if (p[3] != 0) { - hash = (hash << 4) + p[3]; - if (p[4] != 0) { - hash = (hash << 4) + p[4]; - p += 5; - while (*p != 0) { - hash = (hash << 4) + *p++; - hi = hash & 0xf0000000l; - hash ^= hi >> 24; - } - hash &= 0x0fffffffl; - } - } - } - } - return hash; -} - -/* String Destructor */ -static void dtor_string(void *value, int is_key) { - if (is_key) { - free(value); // Since the key and value are the same, we only need to free once. - } -} - hash_table_t *string_table; token_t *token_create_string(c_token_types kind, int lin, int col, const char *s, int len) { @@ -333,6 +295,8 @@ const char *token_name_from_type(c_token_types type) { return "TOK_HASH"; case TOK_ID: return "TOK_ID"; + case TOK_TYPEDEF_NAME: + return "TOK_TYPEDEF_NAME"; case TOK_INTEGER_U32: return "TOK_INTEGER_U32"; case TOK_INTEGER_U64: @@ -430,6 +394,12 @@ void print_token(token_t *tok) { free(escaped); break; } + case TOK_TYPEDEF_NAME: { + char *escaped = re_escape_string(token_string(tok)); + printf("%s: %s@%d:%d\n", name, escaped, tok->line, tok->column); + free(escaped); + break; + } case TOK_CHAR_CONST: printf("%s: '%c'@%d:%d\n", name, token_char(tok), tok->line, tok->column); break; diff --git a/projects/cminus/code/token.h b/projects/cminus/code/token.h @@ -99,6 +99,7 @@ typedef enum { // Identifiers TOK_ID, + TOK_TYPEDEF_NAME, // Constants TOK_INTEGER_U32, // u diff --git a/projects/cminus/code/tokenizer.c b/projects/cminus/code/tokenizer.c @@ -1,5 +1,4 @@ /* tokenizer.c */ -#include <assert.h> #include <ctype.h> #include <errno.h> #include <float.h> @@ -12,11 +11,14 @@ #include "tokenizer.h" #include "token.h" #include "input.h" +#include "util.h" token_t *left_stack[8]; int left_stack_pos = 0; +hash_table_t *typedef_table = NULL; /* Utility Functions */ void init_tokenizer(const char *filename) { input_init(filename); + typedef_table = hash_table_create(16, cmp_string, hash_string, dtor_string); } void destroy_tokenizer(void) { @@ -181,6 +183,8 @@ const char *stringify_type(c_token_types type) { return "#"; case TOK_ID: return "identifier"; + case TOK_TYPEDEF_NAME: + return "typedef name"; case TOK_INTEGER_U32: case TOK_INTEGER_U64: case TOK_INTEGER_S32: @@ -558,6 +562,10 @@ static token_t *read_identifier(void) { if (kind != TOK_ID) { return token_create(kind, line, column, i); } + // Check if it's a typedef + if (hash_table_get(typedef_table, buf) != NULL) { + return token_create(TOK_TYPEDEF_NAME, line, column, i); + } return token_create_string(kind, line, column, buf, i); } diff --git a/projects/cminus/code/util.c b/projects/cminus/code/util.c @@ -0,0 +1,44 @@ +/* util.c */ +#include <string.h> +#include <stdlib.h> +#include "hash_table.h" +/* String Comparison */ +int cmp_string(const void *key1, const void *key2) { + return strcmp((char *)key1, (char *)key2); +} + +/* Hash Function */ +unsigned int hash_string(const void *key) { + unsigned long hash = 0, hi = 0; + const char *p = key; + hash = *p; + if (hash != 0 && p[1] != 0) { + hash = (hash << 4) + p[1]; + if (p[2] != 0) { + hash = (hash << 4) + p[2]; + if (p[3] != 0) { + hash = (hash << 4) + p[3]; + if (p[4] != 0) { + hash = (hash << 4) + p[4]; + p += 5; + while (*p != 0) { + hash = (hash << 4) + *p++; + hi = hash & 0xf0000000l; + hash ^= hi >> 24; + } + hash &= 0x0fffffffl; + } + } + } + } + return hash; +} + +/* String Destructor */ +void dtor_string(void *value, int is_key) { + if (is_key) { + free(value); // Since the key and value are the same, we only need to free once. + } +} + + diff --git a/projects/cminus/code/util.h b/projects/cminus/code/util.h @@ -0,0 +1,9 @@ +/* util.h */ +#ifndef UTIL_H +#define UTIL_H +#include "hash_table.h" +int cmp_string(const void *key1, const void *key2); +unsigned int hash_string(const void *key); +void dtor_string(void *value, int is_key); +#endif + diff --git a/projects/cminus/lexer.html b/projects/cminus/lexer.html @@ -201,9 +201,7 @@ li.L9 { </li> <li>The parser. This takes the tokens and builds an abstract syntax tree (AST). </li> -<li>The symbol table. This exists in a sort of in-between space next to the lexer and parser. It's used to store information about variables and functions. -</li> -<li>The type checker. This is used to ensure that the types of variables and functions are correct. +<li>The type checker/semantic analyzer. This is used to ensure that the types of variables and functions are correct. </li> <li>The code generator. This takes the AST and generates an intermediate representation (IR). </li> @@ -332,7 +330,7 @@ typedef struct token token_t; </pre> -<p class="seealso">Used in sections <a href="lexer.html#1:11">11</a> and <a href="lexer.html#1:40">40</a></p> +<p class="seealso">Used in sections <a href="lexer.html#1:11">11</a> and <a href="lexer.html#1:41">41</a></p> </div> </div> <a name="1:8"><div class="section"><h4 class="noheading">8. </h4></a> @@ -351,7 +349,7 @@ void token_destroy(token_t *token); </pre> -<p class="seealso">Used in section <a href="lexer.html#1:40">40</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:41">41</a></p> </div> </div> <a name="1:9"><div class="section"><h4 class="noheading">9. </h4></a> @@ -372,7 +370,7 @@ void print_token(token_t *tok); </pre> -<p class="seealso">Used in sections <a href="lexer.html#1:11">11</a> and <a href="lexer.html#1:40">40</a></p> +<p class="seealso">Used in sections <a href="lexer.html#1:11">11</a> and <a href="lexer.html#1:41">41</a></p> </div> </div> <a name="1:10"><div class="section"><h4 class="noheading">10. </h4></a> @@ -477,6 +475,7 @@ typedef enum { // Identifiers TOK_ID, + TOK_TYPEDEF_NAME, // Constants TOK_INTEGER_U32, // u @@ -495,7 +494,7 @@ typedef enum { </pre> -<p class="seealso">Used in sections <a href="lexer.html#1:11">11</a> and <a href="lexer.html#1:40">40</a></p> +<p class="seealso">Used in sections <a href="lexer.html#1:11">11</a> and <a href="lexer.html#1:41">41</a></p> </div> </div> <a name="1:11"><div class="section"><h4 class="noheading">11. </h4></a> @@ -517,7 +516,7 @@ extern int line; #endif </pre> -<p class="seealso">Redefined in section <a href="lexer.html#1:40">40</a></p> +<p class="seealso">Redefined in section <a href="lexer.html#1:41">41</a></p> </div> </div> @@ -568,7 +567,7 @@ int line = 1; </pre> -<p class="seealso">Used in section <a href="lexer.html#1:41">41</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:42">42</a></p> </div> </div> <a name="1:13"><div class="section"><h4 class="noheading">13. </h4></a> @@ -598,7 +597,7 @@ double token_float(token_t *token) { } const char *token_string(token_t *token) { - assert(token-&gt;kind == TOK_STRING_ASCII || token-&gt;kind == TOK_ID); + assert(token-&gt;kind == TOK_STRING_ASCII || token-&gt;kind == TOK_ID || token-&gt;kind == TOK_TYPEDEF_NAME); assert(token-&gt;magic == TOK_MAGIC_1); return token_data(token)-&gt;data.s; } @@ -621,7 +620,7 @@ int token_column(token_t *token) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:41">41</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:42">42</a></p> </div> </div> <a name="1:14"><div class="section"><h4 class="noheading">14. </h4></a> @@ -637,7 +636,7 @@ int token_column(token_t *token) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:41">41</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:42">42</a></p> </div> </div> <a name="1:15"><div class="section"><h4 class="noheading">15. </h4></a> @@ -791,6 +790,8 @@ const char *token_name_from_type(c_token_types type) { return "TOK_HASH"; case TOK_ID: return "TOK_ID"; + case TOK_TYPEDEF_NAME: + return "TOK_TYPEDEF_NAME"; case TOK_INTEGER_U32: return "TOK_INTEGER_U32"; case TOK_INTEGER_U64: @@ -910,6 +911,12 @@ void print_token(token_t *tok) { free(escaped); break; } + case TOK_TYPEDEF_NAME: { + char *escaped = re_escape_string(token_string(tok)); + printf("%s: %s@%d:%d\n", name, escaped, tok-&gt;line, tok-&gt;column); + free(escaped); + break; + } case TOK_CHAR_CONST: printf("%s: '%c'@%d:%d\n", name, token_char(tok), tok-&gt;line, tok-&gt;column); break; @@ -998,7 +1005,7 @@ void token_destroy(token_t *token) { </pre> -<p class="seealso">Used in sections <a href="lexer.html#1:11">11</a> and <a href="lexer.html#1:41">41</a></p> +<p class="seealso">Used in sections <a href="lexer.html#1:11">11</a> and <a href="lexer.html#1:42">42</a></p> </div> </div> <a name="1:19"><div class="section"><h4 class="noheading">19. </h4></a> @@ -1015,8 +1022,8 @@ token_t *token_create_string(c_token_types kind, int lin, int col, const char *s } </pre> -<p class="seealso">Redefined in section <a href="lexer.html#1:39">39</a></p> -<p class="seealso">Used in section <a href="lexer.html#1:41">41</a></p> +<p class="seealso">Redefined in section <a href="lexer.html#1:40">40</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:42">42</a></p> </div> </div> <a name="1:20"><div class="section"><h4 class="noheading">20. </h4></a> @@ -1411,7 +1418,7 @@ while (entry) { <div class="codeblock"> <span class="codeblock_name">{Hash Function <a href="lexer.html#1:36">36</a>}</span> <pre class="prettyprint lang-c"> -static unsigned long hash_string(void *key) { +unsigned long hash_string(void *key) { unsigned long hash = 0, g; char *p = key; while (*p) { @@ -1436,7 +1443,7 @@ static unsigned long hash_string(void *key) { <div class="codeblock"> <span class="codeblock_name">{Hash Function <a href="lexer.html#1:36">36</a>} :=</span> <pre class="prettyprint lang-c"> -static unsigned int hash_string(const void *key) { +unsigned int hash_string(const void *key) { unsigned long hash = 0, hi = 0; const char *p = key; hash = *p; @@ -1474,7 +1481,7 @@ static unsigned int hash_string(const void *key) { <div class="codeblock"> <span class="codeblock_name">{String Comparison <a href="lexer.html#1:37">37</a>}</span> <pre class="prettyprint lang-c"> -static int cmp_string(const void *key1, const void *key2) { +int cmp_string(const void *key1, const void *key2) { return strcmp((char *)key1, (char *)key2); } </pre> @@ -1490,7 +1497,7 @@ static int cmp_string(const void *key1, const void *key2) { <div class="codeblock"> <span class="codeblock_name">{String Destructor <a href="lexer.html#1:38">38</a>}</span> <pre class="prettyprint lang-c"> -static void dtor_string(void *value, int is_key) { +void dtor_string(void *value, int is_key) { if (is_key) { free(value); // Since the key and value are the same, we only need to free once. } @@ -1502,6 +1509,41 @@ static void dtor_string(void *value, int is_key) { </div> </div> <a name="1:39"><div class="section"><h4 class="noheading">39. </h4></a> +<p>These functions go in util.c +</p> + +<div class="codeblock"> +<span class="codeblock_name">{<strong>util.c</strong> <a href="lexer.html#1:39">39</a>}</span> +<pre class="prettyprint lang-c"> +#include &lt;string.h&gt; +#include &lt;stdlib.h&gt; +#include "hash_table.h" +<span class="nocode pln">{String Comparison, <a href="lexer.html#1:37">37</a>}</span> +<span class="nocode pln">{Hash Function, <a href="lexer.html#1:36">36</a>}</span> +<span class="nocode pln">{String Destructor, <a href="lexer.html#1:38">38</a>}</span> +</pre> + + + +</div> + +<div class="codeblock"> +<span class="codeblock_name">{<strong>util.h</strong> <a href="lexer.html#1:39">39</a>}</span> +<pre class="prettyprint lang-c"> +#ifndef UTIL_H +#define UTIL_H +#include "hash_table.h" +int cmp_string(const void *key1, const void *key2); +unsigned int hash_string(const void *key); +void dtor_string(void *value, int is_key); +#endif +</pre> + + + +</div> +</div> +<a name="1:40"><div class="section"><h4 class="noheading">40. </h4></a> <p>Now we can implement <code>token_create_string</code> the right way. </p> <p>You might notice that we're using the same key and value. This way of using a hash table is normally called a set. We're using it to store strings, but we could use it to store anything we want to deduplicate. @@ -1510,9 +1552,6 @@ static void dtor_string(void *value, int is_key) { <div class="codeblock"> <span class="codeblock_name">{Token Create String <a href="lexer.html#1:19">19</a>} :=</span> <pre class="prettyprint lang-c"> -<span class="nocode pln">{String Comparison, <a href="lexer.html#1:37">37</a>}</span> -<span class="nocode pln">{Hash Function, <a href="lexer.html#1:36">36</a>}</span> -<span class="nocode pln">{String Destructor, <a href="lexer.html#1:38">38</a>}</span> hash_table_t *string_table; token_t *token_create_string(c_token_types kind, int lin, int col, const char *s, int len) { @@ -1531,10 +1570,10 @@ token_t *token_create_string(c_token_types kind, int lin, int col, </pre> -<p class="seealso">Used in section <a href="lexer.html#1:41">41</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:42">42</a></p> </div> </div> -<a name="1:40"><div class="section"><h4 class="noheading">40. </h4></a> +<a name="1:41"><div class="section"><h4 class="noheading">41. </h4></a> <p>We'll add an external declaration for <code>string_table</code> in <code>token.h</code> so other programs can take advantage of it. </p> @@ -1559,12 +1598,12 @@ extern int line; </div> </div> -<a name="1:41"><div class="section"><h4 class="noheading">41. </h4></a> +<a name="1:42"><div class="section"><h4 class="noheading">42. </h4></a> <p>Finally, we implement the token data structure in <code>token.c</code>. </p> <div class="codeblock"> -<span class="codeblock_name">{<strong>token.c</strong> <a href="lexer.html#1:41">41</a>}</span> +<span class="codeblock_name">{<strong>token.c</strong> <a href="lexer.html#1:42">42</a>}</span> <pre class="prettyprint lang-c"> #include &lt;stdlib.h&gt; #include &lt;string.h&gt; @@ -1573,6 +1612,7 @@ extern int line; #include &lt;ctype.h&gt; #include "token.h" #include "hash_table.h" +#include "util.h" <span class="nocode pln">{Token Data Structure, <a href="lexer.html#1:12">12</a>}</span> <span class="nocode pln">{Token Data Access, <a href="lexer.html#1:13">13</a>}</span> <span class="nocode pln">{Token Creation and Destruction, <a href="lexer.html#1:18">18</a>}</span> @@ -1584,15 +1624,15 @@ extern int line; </div> </div> -<a name="1:42"><div class="section"><h4>42. Input</h4></a> +<a name="1:43"><div class="section"><h4>43. Input</h4></a> <p>Input will provide a simple interface for reading characters from a file. The stream itself is deliberately hidden from the tokenizer, so that the tokenizer doesn't have to worry about buffering or anything like that. </p> </div> -<a name="1:43"><div class="section"><h4 class="noheading">43. </h4></a> +<a name="1:44"><div class="section"><h4 class="noheading">44. </h4></a> <div class="codeblock"> -<span class="codeblock_name">{Input Interface <a href="lexer.html#1:43">43</a>}</span> +<span class="codeblock_name">{Input Interface <a href="lexer.html#1:44">44</a>}</span> <pre class="prettyprint lang-c"> void input_init(const char *filename); int input_getc(void); @@ -1601,7 +1641,7 @@ void input_destroy(void); </pre> -<p class="seealso">Used in section <a href="lexer.html#1:52">52</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:53">53</a></p> </div> <p>When the program wants to start reading a file, it calls <code>input_init</code> with the filename. It can then call <code>input_getc</code> to get the next character in the file. If there's no more input, <code>input_getc</code> will return <code>EOF</code>. </p> @@ -1611,7 +1651,7 @@ void input_destroy(void); </p> </div> -<a name="1:44"><div class="section"><h4>44. Input Design Decisions</h4></a> +<a name="1:45"><div class="section"><h4>45. Input Design Decisions</h4></a> <p>Per rule 1, we're trying to keep memory usage low. That means that instead of reading the entire file into memory, we'll need to read it in chunks. There are a couple of choices for how to do this: </p> <ol> @@ -1628,15 +1668,15 @@ void input_destroy(void); </p> </div> -<a name="1:45"><div class="section"><h4>45. Input Implementation</h4></a> +<a name="1:46"><div class="section"><h4>46. Input Implementation</h4></a> <p>The implementation of the input module is pretty straightforward. We have the following data structures and defines as globals: </p> </div> -<a name="1:46"><div class="section"><h4 class="noheading">46. </h4></a> +<a name="1:47"><div class="section"><h4 class="noheading">47. </h4></a> <div class="codeblock"> -<span class="codeblock_name">{Input Data <a href="lexer.html#1:46">46</a>}</span> +<span class="codeblock_name">{Input Data <a href="lexer.html#1:47">47</a>}</span> <pre class="prettyprint lang-c"> #define CHUNK_SIZE 128 static char buffer[CHUNK_SIZE]; @@ -1649,16 +1689,16 @@ static FILE *file = NULL; </pre> -<p class="seealso">Used in section <a href="lexer.html#1:51">51</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:52">52</a></p> </div> <p>When the program calls <code>input_init</code>, we open the file. </p> </div> -<a name="1:47"><div class="section"><h4 class="noheading">47. </h4></a> +<a name="1:48"><div class="section"><h4 class="noheading">48. </h4></a> <div class="codeblock"> -<span class="codeblock_name">{Input Initialization <a href="lexer.html#1:47">47</a>}</span> +<span class="codeblock_name">{Input Initialization <a href="lexer.html#1:48">48</a>}</span> <pre class="prettyprint lang-c"> void input_init(const char *filename) { file = fopen(filename, "r"); @@ -1670,16 +1710,16 @@ void input_init(const char *filename) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:51">51</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:52">52</a></p> </div> <p>When the program calls <code>input_getc</code>, we return the next character in the buffer. If the buffer is exhausted, we call <code>nextline</code>. We also track the line and column. </p> </div> -<a name="1:48"><div class="section"><h4 class="noheading">48. </h4></a> +<a name="1:49"><div class="section"><h4 class="noheading">49. </h4></a> <div class="codeblock"> -<span class="codeblock_name">{Input Get Character <a href="lexer.html#1:48">48</a>}</span> +<span class="codeblock_name">{Input Get Character <a href="lexer.html#1:49">49</a>}</span> <pre class="prettyprint lang-c"> int input_getc(void) { if (unget_buffer_stack_pos &gt; 0) { @@ -1698,16 +1738,16 @@ int input_getc(void) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:51">51</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:52">52</a></p> </div> <p>When the program calls <code>input_ungetc</code>, we save the character in the <code>unget_buffer</code>. </p> </div> -<a name="1:49"><div class="section"><h4 class="noheading">49. </h4></a> +<a name="1:50"><div class="section"><h4 class="noheading">50. </h4></a> <div class="codeblock"> -<span class="codeblock_name">{Input Unget Character <a href="lexer.html#1:49">49</a>}</span> +<span class="codeblock_name">{Input Unget Character <a href="lexer.html#1:50">50</a>}</span> <pre class="prettyprint lang-c"> void input_ungetc(int c) { unget_buffer_stack[unget_buffer_stack_pos++] = c; @@ -1715,16 +1755,16 @@ void input_ungetc(int c) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:51">51</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:52">52</a></p> </div> <p>Since we're not using dynamic memory allocation, cleanup is pretty simple. </p> </div> -<a name="1:50"><div class="section"><h4 class="noheading">50. </h4></a> +<a name="1:51"><div class="section"><h4 class="noheading">51. </h4></a> <div class="codeblock"> -<span class="codeblock_name">{Input Destroy <a href="lexer.html#1:50">50</a>}</span> +<span class="codeblock_name">{Input Destroy <a href="lexer.html#1:51">51</a>}</span> <pre class="prettyprint lang-c"> void input_destroy(void) { fclose(file); @@ -1732,40 +1772,40 @@ void input_destroy(void) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:51">51</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:52">52</a></p> </div> </div> -<a name="1:51"><div class="section"><h4 class="noheading">51. </h4></a> +<a name="1:52"><div class="section"><h4 class="noheading">52. </h4></a> <p>We put the whole thing together in <code>input.c</code>. </p> <div class="codeblock"> -<span class="codeblock_name">{<strong>input.c</strong> <a href="lexer.html#1:51">51</a>}</span> +<span class="codeblock_name">{<strong>input.c</strong> <a href="lexer.html#1:52">52</a>}</span> <pre class="prettyprint lang-c"> #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include "input.h" -<span class="nocode pln">{Input Data, <a href="lexer.html#1:46">46</a>}</span> -<span class="nocode pln">{Input Initialization, <a href="lexer.html#1:47">47</a>}</span> -<span class="nocode pln">{Input Get Character, <a href="lexer.html#1:48">48</a>}</span> -<span class="nocode pln">{Input Unget Character, <a href="lexer.html#1:49">49</a>}</span> -<span class="nocode pln">{Input Destroy, <a href="lexer.html#1:50">50</a>}</span> +<span class="nocode pln">{Input Data, <a href="lexer.html#1:47">47</a>}</span> +<span class="nocode pln">{Input Initialization, <a href="lexer.html#1:48">48</a>}</span> +<span class="nocode pln">{Input Get Character, <a href="lexer.html#1:49">49</a>}</span> +<span class="nocode pln">{Input Unget Character, <a href="lexer.html#1:50">50</a>}</span> +<span class="nocode pln">{Input Destroy, <a href="lexer.html#1:51">51</a>}</span> </pre> </div> </div> -<a name="1:52"><div class="section"><h4 class="noheading">52. </h4></a> +<a name="1:53"><div class="section"><h4 class="noheading">53. </h4></a> <p>We'll need an external declaration for <code>file</code> in <code>input.h</code> so other programs can take advantage of it. </p> <div class="codeblock"> -<span class="codeblock_name">{<strong>input.h</strong> <a href="lexer.html#1:52">52</a>}</span> +<span class="codeblock_name">{<strong>input.h</strong> <a href="lexer.html#1:53">53</a>}</span> <pre class="prettyprint lang-c"> #ifndef INPUT_H #define INPUT_H -<span class="nocode pln">{Input Interface, <a href="lexer.html#1:43">43</a>}</span> +<span class="nocode pln">{Input Interface, <a href="lexer.html#1:44">44</a>}</span> #endif </pre> @@ -1773,18 +1813,18 @@ void input_destroy(void) { </div> </div> -<a name="1:53"><div class="section"><h4 class="noheading">53. </h4></a> +<a name="1:54"><div class="section"><h4 class="noheading">54. </h4></a> <p>We'll implement the lexer interface in <code>tokenizer.h</code> </p> <div class="codeblock"> -<span class="codeblock_name">{<strong>tokenizer.h</strong> <a href="lexer.html#1:53">53</a>}</span> +<span class="codeblock_name">{<strong>tokenizer.h</strong> <a href="lexer.html#1:54">54</a>}</span> <pre class="prettyprint lang-c"> #ifndef TOKENIZER_H #define TOKENIZER_H #include "token.h" #include "input.h" -<span class="nocode pln">{Tokenization Interface, <a href="lexer.html#1:54">54</a>}</span> +<span class="nocode pln">{Tokenization Interface, <a href="lexer.html#1:55">55</a>}</span> #endif </pre> @@ -1792,7 +1832,7 @@ void input_destroy(void) { </div> </div> -<a name="1:54"><div class="section"><h4 class="noheading">54. </h4></a> +<a name="1:55"><div class="section"><h4 class="noheading">55. </h4></a> <p>The tokenization interface will have a couple of functions. <code>next_token</code> will return the next token in the input stream, <code>init_tokenizer</code> will initialize the tokenizer, and <code>destroy_tokenizer</code> will clean up. </p> <p>We'll also have some helper functions for lookahead and matching. @@ -1803,7 +1843,7 @@ void input_destroy(void) { </p> <div class="codeblock"> -<span class="codeblock_name">{Tokenization Interface <a href="lexer.html#1:54">54</a>}</span> +<span class="codeblock_name">{Tokenization Interface <a href="lexer.html#1:55">55</a>}</span> <pre class="prettyprint lang-c"> void init_tokenizer(const char *filename); void destroy_tokenizer(void); @@ -1815,17 +1855,16 @@ void consume_alt(c_token_types *kinds, int n); </pre> -<p class="seealso">Used in section <a href="lexer.html#1:53">53</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:54">54</a></p> </div> </div> -<a name="1:55"><div class="section"><h4 class="noheading">55. </h4></a> -<p>Now we can finally implement the tokenizer. +<a name="1:56"><div class="section"><h4 class="noheading">56. </h4></a> +<p>Now we can finally implement the tokenizer. A stack for storing tokens for lookahead is defined, as is a hash table, modified by the parser, for typedefs. </p> <div class="codeblock"> -<span class="codeblock_name">{<strong>tokenizer.c</strong> <a href="lexer.html#1:55">55</a>}</span> +<span class="codeblock_name">{<strong>tokenizer.c</strong> <a href="lexer.html#1:56">56</a>}</span> <pre class="prettyprint lang-c"> -#include &lt;assert.h&gt; #include &lt;ctype.h&gt; #include &lt;errno.h&gt; #include &lt;float.h&gt; @@ -1838,25 +1877,28 @@ void consume_alt(c_token_types *kinds, int n); #include "tokenizer.h" #include "token.h" #include "input.h" +#include "util.h" token_t *left_stack[8]; int left_stack_pos = 0; -<span class="nocode pln">{Utility Functions, <a href="lexer.html#1:56">56</a>}</span> -<span class="nocode pln">{Tokenization Function, <a href="lexer.html#1:58">58</a>}</span> +hash_table_t *typedef_table = NULL; +<span class="nocode pln">{Utility Functions, <a href="lexer.html#1:57">57</a>}</span> +<span class="nocode pln">{Tokenization Function, <a href="lexer.html#1:59">59</a>}</span> </pre> </div> </div> -<a name="1:56"><div class="section"><h4 class="noheading">56. </h4></a> +<a name="1:57"><div class="section"><h4 class="noheading">57. </h4></a> <p>Utility functions are everything that doesn't directly tokenize the input. </p> <div class="codeblock"> -<span class="codeblock_name">{Utility Functions <a href="lexer.html#1:56">56</a>}</span> +<span class="codeblock_name">{Utility Functions <a href="lexer.html#1:57">57</a>}</span> <pre class="prettyprint lang-c"> void init_tokenizer(const char *filename) { input_init(filename); + typedef_table = hash_table_create(16, cmp_string, hash_string, dtor_string); } void destroy_tokenizer(void) { @@ -1876,7 +1918,7 @@ token_t *peek_token(void) { return token; } -<span class="nocode pln">{Stringify Type, <a href="lexer.html#1:57">57</a>}</span> +<span class="nocode pln">{Stringify Type, <a href="lexer.html#1:58">58</a>}</span> void consume(c_token_types kind) { token_t *token = next_token(); @@ -1905,15 +1947,15 @@ void consume_alt(c_token_types *kinds, int n) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:55">55</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:56">56</a></p> </div> </div> -<a name="1:57"><div class="section"><h4 class="noheading">57. </h4></a> +<a name="1:58"><div class="section"><h4 class="noheading">58. </h4></a> <p>We'll need a helper function to convert token types to strings. It's pretty simple, just tedious. </p> <div class="codeblock"> -<span class="codeblock_name">{Stringify Type <a href="lexer.html#1:57">57</a>}</span> +<span class="codeblock_name">{Stringify Type <a href="lexer.html#1:58">58</a>}</span> <pre class="prettyprint lang-c"> const char *stringify_type(c_token_types type) { switch (type) { @@ -2059,6 +2101,8 @@ const char *stringify_type(c_token_types type) { return "#"; case TOK_ID: return "identifier"; + case TOK_TYPEDEF_NAME: + return "typedef name"; case TOK_INTEGER_U32: case TOK_INTEGER_U64: case TOK_INTEGER_S32: @@ -2101,25 +2145,25 @@ const char *stringify_type(c_token_types type) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:56">56</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:57">57</a></p> </div> </div> -<a name="1:58"><div class="section"><h4 class="noheading">58. </h4></a> +<a name="1:59"><div class="section"><h4 class="noheading">59. </h4></a> <p>Now we can implement the tokenization function. The pattern is pretty simple: we call each of the tokenization functions in turn until we find a match. If we don't find a match, we print an error message and exit. You might wonder why skip_whitespace can return a token. This makes handling the divide operator easier as comments also start with a slash. </p> <div class="codeblock"> -<span class="codeblock_name">{Tokenization Function <a href="lexer.html#1:58">58</a>}</span> +<span class="codeblock_name">{Tokenization Function <a href="lexer.html#1:59">59</a>}</span> <pre class="prettyprint lang-c"> char file_name[1024]; -<span class="nocode pln">{Warning/Error Functions, <a href="lexer.html#1:59">59</a>}</span> -<span class="nocode pln">{Skip Whitespace, <a href="lexer.html#1:60">60</a>}</span> -<span class="nocode pln">{Tokenize Identifier, <a href="lexer.html#1:61">61</a>}</span> -<span class="nocode pln">{Tokenize Number, <a href="lexer.html#1:64">64</a>}</span> -<span class="nocode pln">{Tokenize String, <a href="lexer.html#1:73">73</a>}</span> -<span class="nocode pln">{Tokenize Character, <a href="lexer.html#1:72">72</a>}</span> -<span class="nocode pln">{Tokenize Operator, <a href="lexer.html#1:63">63</a>}</span> +<span class="nocode pln">{Warning/Error Functions, <a href="lexer.html#1:60">60</a>}</span> +<span class="nocode pln">{Skip Whitespace, <a href="lexer.html#1:61">61</a>}</span> +<span class="nocode pln">{Tokenize Identifier, <a href="lexer.html#1:62">62</a>}</span> +<span class="nocode pln">{Tokenize Number, <a href="lexer.html#1:65">65</a>}</span> +<span class="nocode pln">{Tokenize String, <a href="lexer.html#1:74">74</a>}</span> +<span class="nocode pln">{Tokenize Character, <a href="lexer.html#1:73">73</a>}</span> +<span class="nocode pln">{Tokenize Operator, <a href="lexer.html#1:64">64</a>}</span> token_t *next_token(void) { if (left_stack_pos &gt; 0) { return left_stack[--left_stack_pos]; @@ -2159,20 +2203,20 @@ token_t *next_token(void) { } #ifdef TEST_TOKENIZER -<span class="nocode pln">{Run Test, <a href="lexer.html#1:75">75</a>}</span> +<span class="nocode pln">{Run Test, <a href="lexer.html#1:76">76</a>}</span> #endif </pre> -<p class="seealso">Used in section <a href="lexer.html#1:55">55</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:56">56</a></p> </div> </div> -<a name="1:59"><div class="section"><h4 class="noheading">59. </h4></a> +<a name="1:60"><div class="section"><h4 class="noheading">60. </h4></a> <p>We'll need a couple of helper functions to skip whitespace and print warnings/errors. </p> <div class="codeblock"> -<span class="codeblock_name">{Warning/Error Functions <a href="lexer.html#1:59">59</a>}</span> +<span class="codeblock_name">{Warning/Error Functions <a href="lexer.html#1:60">60</a>}</span> <pre class="prettyprint lang-c"> void tok_error(const char *fmt, ...) { va_list args; @@ -2194,15 +2238,15 @@ void tok_warn(const char *fmt, ...) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:58">58</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:59">59</a></p> </div> </div> -<a name="1:60"><div class="section"><h4 class="noheading">60. </h4></a> +<a name="1:61"><div class="section"><h4 class="noheading">61. </h4></a> <p>The <code>skip_whitespace</code> function is pretty simple. It just skips over any comments, whitespace, and line directives. </p> <div class="codeblock"> -<span class="codeblock_name">{Skip Whitespace <a href="lexer.html#1:60">60</a>}</span> +<span class="codeblock_name">{Skip Whitespace <a href="lexer.html#1:61">61</a>}</span> <pre class="prettyprint lang-c"> static token_t *skip_whitespace(void) { int c; @@ -2275,17 +2319,17 @@ static token_t *skip_whitespace(void) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:58">58</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:59">59</a></p> </div> </div> -<a name="1:61"><div class="section"><h4 class="noheading">61. </h4></a> +<a name="1:62"><div class="section"><h4 class="noheading">62. </h4></a> <p>The <code>read_identifier</code> function reads an identifier from the input stream. C identifiers can contain letters, digits, and underscores, but they can't start with a digit. </p> <div class="codeblock"> -<span class="codeblock_name">{Tokenize Identifier <a href="lexer.html#1:61">61</a>}</span> +<span class="codeblock_name">{Tokenize Identifier <a href="lexer.html#1:62">62</a>}</span> <pre class="prettyprint lang-c"> -<span class="nocode pln">{Get Keyword, <a href="lexer.html#1:62">62</a>}</span> +<span class="nocode pln">{Get Keyword, <a href="lexer.html#1:63">63</a>}</span> static token_t *read_identifier(void) { int c; char buf[1024]; @@ -2314,20 +2358,24 @@ static token_t *read_identifier(void) { if (kind != TOK_ID) { return token_create(kind, line, column, i); } + // Check if it's a typedef + if (hash_table_get(typedef_table, buf) != NULL) { + return token_create(TOK_TYPEDEF_NAME, line, column, i); + } return token_create_string(kind, line, column, buf, i); } </pre> -<p class="seealso">Used in section <a href="lexer.html#1:58">58</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:59">59</a></p> </div> </div> -<a name="1:62"><div class="section"><h4 class="noheading">62. </h4></a> +<a name="1:63"><div class="section"><h4 class="noheading">63. </h4></a> <p>The <code>get_keyword</code> function is a simple decision tree for identifying keywords. The code is pretty tedious, but it works. </p> <div class="codeblock"> -<span class="codeblock_name">{Get Keyword <a href="lexer.html#1:62">62</a>}</span> +<span class="codeblock_name">{Get Keyword <a href="lexer.html#1:63">63</a>}</span> <pre class="prettyprint lang-c"> c_token_types get_keyword(const char *buf, int len) { switch (buf[0]) { @@ -2521,15 +2569,15 @@ c_token_types get_keyword(const char *buf, int len) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:61">61</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:62">62</a></p> </div> </div> -<a name="1:63"><div class="section"><h4 class="noheading">63. </h4></a> +<a name="1:64"><div class="section"><h4 class="noheading">64. </h4></a> <p>The <code>read_operator</code> function works similarly to the <code>read_identifier</code> function. It uses a decision tree to identify operators. </p> <div class="codeblock"> -<span class="codeblock_name">{Tokenize Operator <a href="lexer.html#1:63">63</a>}</span> +<span class="codeblock_name">{Tokenize Operator <a href="lexer.html#1:64">64</a>}</span> <pre class="prettyprint lang-c"> token_t *read_operator(void) { @@ -2691,50 +2739,50 @@ token_t *read_operator(void) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:58">58</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:59">59</a></p> </div> </div> -<a name="1:64"><div class="section"><h4 class="noheading">64. </h4></a> +<a name="1:65"><div class="section"><h4 class="noheading">65. </h4></a> <p>The <code>read_number</code> function reads a number from the input stream. It can be an integer or a floating-point number. </p> <p>I've broken it up a bit to make it easier to read. </p> <div class="codeblock"> -<span class="codeblock_name">{Tokenize Number <a href="lexer.html#1:64">64</a>}</span> +<span class="codeblock_name">{Tokenize Number <a href="lexer.html#1:65">65</a>}</span> <pre class="prettyprint lang-c"> static token_t *read_number(void) { int c; char buf[1024]; int i = 0; c = input_getc(); -<span class="nocode pln"> {Check for valid prefix, <a href="lexer.html#1:65">65</a>}</span> +<span class="nocode pln"> {Check for valid prefix, <a href="lexer.html#1:66">66</a>}</span> int radix = 10; -<span class="nocode pln"> {Process Radix, <a href="lexer.html#1:66">66</a>}</span> +<span class="nocode pln"> {Process Radix, <a href="lexer.html#1:67">67</a>}</span> int is_float = 0; -<span class="nocode pln"> {Read Number Loop, <a href="lexer.html#1:67">67</a>}</span> +<span class="nocode pln"> {Read Number Loop, <a href="lexer.html#1:68">68</a>}</span> buf[i] = '\0'; -<span class="nocode pln"> {Process Suffixes, <a href="lexer.html#1:68">68</a>}</span> -<span class="nocode pln"> {Check for conflicting suffixes, <a href="lexer.html#1:69">69</a>}</span> +<span class="nocode pln"> {Process Suffixes, <a href="lexer.html#1:69">69</a>}</span> +<span class="nocode pln"> {Check for conflicting suffixes, <a href="lexer.html#1:70">70</a>}</span> if (is_float) { -<span class="nocode pln"> {Convert to float, <a href="lexer.html#1:70">70</a>}</span> +<span class="nocode pln"> {Convert to float, <a href="lexer.html#1:71">71</a>}</span> } else { -<span class="nocode pln"> {Convert to integer, <a href="lexer.html#1:71">71</a>}</span> +<span class="nocode pln"> {Convert to integer, <a href="lexer.html#1:72">72</a>}</span> } return NULL; } </pre> -<p class="seealso">Used in section <a href="lexer.html#1:58">58</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:59">59</a></p> </div> </div> -<a name="1:65"><div class="section"><h4 class="noheading">65. </h4></a> +<a name="1:66"><div class="section"><h4 class="noheading">66. </h4></a> <p>To determine if a character is a valid prefix for a number, we need to check if it's a digit or a period followed by a digit </p> <div class="codeblock"> -<span class="codeblock_name">{Check for valid prefix <a href="lexer.html#1:65">65</a>}</span> +<span class="codeblock_name">{Check for valid prefix <a href="lexer.html#1:66">66</a>}</span> <pre class="prettyprint lang-c"> // If we don't have a digit or decimal point, it's not a number if (!isdigit(c) &amp;&amp; c != '.') { @@ -2753,15 +2801,15 @@ static token_t *read_number(void) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:64">64</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:65">65</a></p> </div> </div> -<a name="1:66"><div class="section"><h4 class="noheading">66. </h4></a> +<a name="1:67"><div class="section"><h4 class="noheading">67. </h4></a> <p>A C constant starting with a zero is either an octal or hexadecimal constant. We need to check the next character to determine which one it is. </p> <div class="codeblock"> -<span class="codeblock_name">{Process Radix <a href="lexer.html#1:66">66</a>}</span> +<span class="codeblock_name">{Process Radix <a href="lexer.html#1:67">67</a>}</span> <pre class="prettyprint lang-c"> // Check for hex and octal. if (c == '0') { @@ -2781,13 +2829,13 @@ static token_t *read_number(void) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:64">64</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:65">65</a></p> </div> </div> -<a name="1:67"><div class="section"><h4 class="noheading">67. </h4></a> +<a name="1:68"><div class="section"><h4 class="noheading">68. </h4></a> <div class="codeblock"> -<span class="codeblock_name">{Read Number Loop <a href="lexer.html#1:67">67</a>}</span> +<span class="codeblock_name">{Read Number Loop <a href="lexer.html#1:68">68</a>}</span> <pre class="prettyprint lang-c"> while ((c = input_getc()) != EOF) { // Since there can be multiple writes to the buffer, we want to make sure we @@ -2837,15 +2885,15 @@ static token_t *read_number(void) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:64">64</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:65">65</a></p> </div> </div> -<a name="1:68"><div class="section"><h4 class="noheading">68. </h4></a> +<a name="1:69"><div class="section"><h4 class="noheading">69. </h4></a> <p>C constants can have suffixes to indicate their type. We need to check for these suffixes and set the appropriate flags. </p> <div class="codeblock"> -<span class="codeblock_name">{Process Suffixes <a href="lexer.html#1:68">68</a>}</span> +<span class="codeblock_name">{Process Suffixes <a href="lexer.html#1:69">69</a>}</span> <pre class="prettyprint lang-c"> int is_unsigned = 0; int is_long = 0; @@ -2878,15 +2926,15 @@ static token_t *read_number(void) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:64">64</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:65">65</a></p> </div> </div> -<a name="1:69"><div class="section"><h4 class="noheading">69. </h4></a> +<a name="1:70"><div class="section"><h4 class="noheading">70. </h4></a> <p>If we find conflicting suffixes, we print a warning and ignore the suffixes. </p> <div class="codeblock"> -<span class="codeblock_name">{Check for conflicting suffixes <a href="lexer.html#1:69">69</a>}</span> +<span class="codeblock_name">{Check for conflicting suffixes <a href="lexer.html#1:70">70</a>}</span> <pre class="prettyprint lang-c"> if (is_single &amp;&amp; is_long) { tok_warn("Warning: Invalid suffixes 'l' and 'f' for floating point " @@ -2906,15 +2954,15 @@ static token_t *read_number(void) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:64">64</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:65">65</a></p> </div> </div> -<a name="1:70"><div class="section"><h4 class="noheading">70. </h4></a> +<a name="1:71"><div class="section"><h4 class="noheading">71. </h4></a> <p>If the string contains a float, we pass it to strtod. We need to make sure that the number is in range for the given type and check for errors from strtod </p> <div class="codeblock"> -<span class="codeblock_name">{Convert to float <a href="lexer.html#1:70">70</a>}</span> +<span class="codeblock_name">{Convert to float <a href="lexer.html#1:71">71</a>}</span> <pre class="prettyprint lang-c"> errno = 0; // Strtod generates a unix-style error when it's given something out of @@ -2944,15 +2992,15 @@ static token_t *read_number(void) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:64">64</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:65">65</a></p> </div> </div> -<a name="1:71"><div class="section"><h4 class="noheading">71. </h4></a> +<a name="1:72"><div class="section"><h4 class="noheading">72. </h4></a> <p>If the string contains a number, we pass it to stroll. We need to make sure that the number is in range for the given type and check for errors from strtoll </p> <div class="codeblock"> -<span class="codeblock_name">{Convert to integer <a href="lexer.html#1:71">71</a>}</span> +<span class="codeblock_name">{Convert to integer <a href="lexer.html#1:72">72</a>}</span> <pre class="prettyprint lang-c"> errno = 0; uint64_t int_ = strtoull(buf, NULL, radix); @@ -2994,15 +3042,15 @@ static token_t *read_number(void) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:64">64</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:65">65</a></p> </div> </div> -<a name="1:72"><div class="section"><h4 class="noheading">72. </h4></a> +<a name="1:73"><div class="section"><h4 class="noheading">73. </h4></a> <p>The <code>read_char_constant</code> function reads a character constant from the input stream. It can be a single character or a multi-character escape sequence. </p> <div class="codeblock"> -<span class="codeblock_name">{Tokenize Character <a href="lexer.html#1:72">72</a>}</span> +<span class="codeblock_name">{Tokenize Character <a href="lexer.html#1:73">73</a>}</span> <pre class="prettyprint lang-c"> static token_t *read_char_constant(void) { int c; @@ -3033,10 +3081,10 @@ static token_t *read_char_constant(void) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:58">58</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:59">59</a></p> </div> </div> -<a name="1:73"><div class="section"><h4 class="noheading">73. </h4></a> +<a name="1:74"><div class="section"><h4 class="noheading">74. </h4></a> <p>The <code>read_string_literal</code> function reads a string literal from the input stream. </p> <p>For this function, an automatic-lifetime buffer is used to store the string it becomes too large. At that point, a heap-allocated buffer is used. @@ -3044,9 +3092,9 @@ This way we can avoid unnecessary heap allocations for small strings. </p> <div class="codeblock"> -<span class="codeblock_name">{Tokenize String <a href="lexer.html#1:73">73</a>}</span> +<span class="codeblock_name">{Tokenize String <a href="lexer.html#1:74">74</a>}</span> <pre class="prettyprint lang-c"> -<span class="nocode pln">{Read Escape Sequence, <a href="lexer.html#1:74">74</a>}</span> +<span class="nocode pln">{Read Escape Sequence, <a href="lexer.html#1:75">75</a>}</span> static token_t *read_string_literal(void) { int c; c = input_getc(); @@ -3105,15 +3153,15 @@ static token_t *read_string_literal(void) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:58">58</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:59">59</a></p> </div> </div> -<a name="1:74"><div class="section"><h4 class="noheading">74. </h4></a> +<a name="1:75"><div class="section"><h4 class="noheading">75. </h4></a> <p>Escape sequences in C can either be single characters or octal/hexadecimal values. We need to handle both cases. </p> <div class="codeblock"> -<span class="codeblock_name">{Read Escape Sequence <a href="lexer.html#1:74">74</a>}</span> +<span class="codeblock_name">{Read Escape Sequence <a href="lexer.html#1:75">75</a>}</span> <pre class="prettyprint lang-c"> static char read_escape_sequence(int *len) { int c = input_getc(); @@ -3176,15 +3224,15 @@ static char read_escape_sequence(int *len) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:73">73</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:74">74</a></p> </div> </div> -<a name="1:75"><div class="section"><h4 class="noheading">75. </h4></a> +<a name="1:76"><div class="section"><h4 class="noheading">76. </h4></a> <p>Finally, I'll add some code for running the tokenizer as its own program. This way we can test it out. </p> <div class="codeblock"> -<span class="codeblock_name">{Run Test <a href="lexer.html#1:75">75</a>}</span> +<span class="codeblock_name">{Run Test <a href="lexer.html#1:76">76</a>}</span> <pre class="prettyprint lang-c"> char *preprocess(char *in) { char *output_name = malloc(1024); @@ -3219,7 +3267,7 @@ int main(int argc, char **argv) { </pre> -<p class="seealso">Used in section <a href="lexer.html#1:58">58</a></p> +<p class="seealso">Used in section <a href="lexer.html#1:59">59</a></p> </div> <h3> Bugs/Errata</h3> <p>I wrote this code in a single sitting, so there are bound to be bugs. I'll list them here as I find them. The code you see here is the final version, with all bugs fixed. diff --git a/projects/cminus/parser.html b/projects/cminus/parser.html @@ -0,0 +1,251 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Parser</title> +<script> +!function(){var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; +(function(){function R(a){function d(e){var b=e.charCodeAt(0);if(b!==92)return b;var a=e.charAt(1);return(b=r[a])?b:"0"<=a&&a<="7"?parseInt(e.substring(1),8):a==="u"||a==="x"?parseInt(e.substring(2),16):e.charCodeAt(1)}function g(e){if(e<32)return(e<16?"\\x0":"\\x")+e.toString(16);e=String.fromCharCode(e);return e==="\\"||e==="-"||e==="]"||e==="^"?"\\"+e:e}function b(e){var b=e.substring(1,e.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),e=[],a= +b[0]==="^",c=["["];a&&c.push("^");for(var a=a?1:0,f=b.length;a<f;++a){var h=b[a];if(/\\[bdsw]/i.test(h))c.push(h);else{var h=d(h),l;a+2<f&&"-"===b[a+1]?(l=d(b[a+2]),a+=2):l=h;e.push([h,l]);l<65||h>122||(l<65||h>90||e.push([Math.max(65,h)|32,Math.min(l,90)|32]),l<97||h>122||e.push([Math.max(97,h)&-33,Math.min(l,122)&-33]))}}e.sort(function(e,a){return e[0]-a[0]||a[1]-e[1]});b=[];f=[];for(a=0;a<e.length;++a)h=e[a],h[0]<=f[1]+1?f[1]=Math.max(f[1],h[1]):b.push(f=h);for(a=0;a<b.length;++a)h=b[a],c.push(g(h[0])), +h[1]>h[0]&&(h[1]+1>h[0]&&c.push("-"),c.push(g(h[1])));c.push("]");return c.join("")}function s(e){for(var a=e.source.match(/\[(?:[^\\\] ]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),c=a.length,d=[],f=0,h=0;f<c;++f){var l=a[f];l==="("?++h:"\\"===l.charAt(0)&&(l=+l.substring(1))&&(l<=h?d[l]=-1:a[f]=g(l))}for(f=1;f<d.length;++f)-1===d[f]&&(d[f]=++x);for(h=f=0;f<c;++f)l=a[f],l==="("?(++h,d[h]||(a[f]="(?:")):"\\"===l.charAt(0)&&(l=+l.substring(1))&&l<=h&& +(a[f]="\\"+d[l]);for(f=0;f<c;++f)"^"===a[f]&&"^"!==a[f+1]&&(a[f]="");if(e.ignoreCase&&m)for(f=0;f<c;++f)l=a[f],e=l.charAt(0),l.length>=2&&e==="["?a[f]=b(l):e!=="\\"&&(a[f]=l.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return a.join("")}for(var x=0,m=!1,j=!1,k=0,c=a.length;k<c;++k){var i=a[k];if(i.ignoreCase)j=!0;else if(/[a-z]/i.test(i.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){m=!0;j=!1;break}}for(var r={b:8,t:9,n:10,v:11, +f:12,r:13},n=[],k=0,c=a.length;k<c;++k){i=a[k];if(i.global||i.multiline)throw Error(""+i);n.push("(?:"+s(i)+")")}return RegExp(n.join("|"),j?"gi":"g")}function S(a,d){function g(a){var c=a.nodeType;if(c==1){if(!b.test(a.className)){for(c=a.firstChild;c;c=c.nextSibling)g(c);c=a.nodeName.toLowerCase();if("br"===c||"li"===c)s[j]="\n",m[j<<1]=x++,m[j++<<1|1]=a}}else if(c==3||c==4)c=a.nodeValue,c.length&&(c=d?c.replace(/\r\n?/g,"\n"):c.replace(/[\t\n\r ]+/g," "),s[j]=c,m[j<<1]=x,x+=c.length,m[j++<<1|1]= +a)}var b=/(?:^|\s)nocode(?:\s|$)/,s=[],x=0,m=[],j=0;g(a);return{a:s.join("").replace(/\n$/,""),d:m}}function H(a,d,g,b){d&&(a={a:d,e:a},g(a),b.push.apply(b,a.g))}function T(a){for(var d=void 0,g=a.firstChild;g;g=g.nextSibling)var b=g.nodeType,d=b===1?d?a:g:b===3?U.test(g.nodeValue)?a:d:d;return d===a?void 0:d}function D(a,d){function g(a){for(var j=a.e,k=[j,"pln"],c=0,i=a.a.match(s)||[],r={},n=0,e=i.length;n<e;++n){var z=i[n],w=r[z],t=void 0,f;if(typeof w==="string")f=!1;else{var h=b[z.charAt(0)]; +if(h)t=z.match(h[1]),w=h[0];else{for(f=0;f<x;++f)if(h=d[f],t=z.match(h[1])){w=h[0];break}t||(w="pln")}if((f=w.length>=5&&"lang-"===w.substring(0,5))&&!(t&&typeof t[1]==="string"))f=!1,w="src";f||(r[z]=w)}h=c;c+=z.length;if(f){f=t[1];var l=z.indexOf(f),B=l+f.length;t[2]&&(B=z.length-t[2].length,l=B-f.length);w=w.substring(5);H(j+h,z.substring(0,l),g,k);H(j+h+l,f,I(w,f),k);H(j+h+B,z.substring(B),g,k)}else k.push(j+h,w)}a.g=k}var b={},s;(function(){for(var g=a.concat(d),j=[],k={},c=0,i=g.length;c<i;++c){var r= +g[c],n=r[3];if(n)for(var e=n.length;--e>=0;)b[n.charAt(e)]=r;r=r[1];n=""+r;k.hasOwnProperty(n)||(j.push(r),k[n]=q)}j.push(/[\S\s]/);s=R(j)})();var x=d.length;return g}function v(a){var d=[],g=[];a.tripleQuotedStrings?d.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?d.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, +q,"'\"`"]):d.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&g.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var b=a.hashComments;b&&(a.cStyleComments?(b>1?d.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):d.push(["com",/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),g.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,q])):d.push(["com", +/^#[^\n\r]*/,q,"#"]));a.cStyleComments&&(g.push(["com",/^\/\/[^\n\r]*/,q]),g.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));if(b=a.regexLiterals){var s=(b=b>1?"":"\n\r")?".":"[\\S\\s]";g.push(["lang-regex",RegExp("^(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*("+("/(?=[^/*"+b+"])(?:[^/\\x5B\\x5C"+b+"]|\\x5C"+s+"|\\x5B(?:[^\\x5C\\x5D"+b+"]|\\x5C"+ +s+")*(?:\\x5D|$))+/")+")")])}(b=a.types)&&g.push(["typ",b]);b=(""+a.keywords).replace(/^ | $/g,"");b.length&&g.push(["kwd",RegExp("^(?:"+b.replace(/[\s,]+/g,"|")+")\\b"),q]);d.push(["pln",/^\s+/,q," \r\n\t\u00a0"]);b="^.[^\\s\\w.$@'\"`/\\\\]*";a.regexLiterals&&(b+="(?!s*/)");g.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/, +q],["pun",RegExp(b),q]);return D(d,g)}function J(a,d,g){function b(a){var c=a.nodeType;if(c==1&&!x.test(a.className))if("br"===a.nodeName)s(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)b(a);else if((c==3||c==4)&&g){var d=a.nodeValue,i=d.match(m);if(i)c=d.substring(0,i.index),a.nodeValue=c,(d=d.substring(i.index+i[0].length))&&a.parentNode.insertBefore(j.createTextNode(d),a.nextSibling),s(a),c||a.parentNode.removeChild(a)}}function s(a){function b(a,c){var d= +c?a.cloneNode(!1):a,e=a.parentNode;if(e){var e=b(e,1),g=a.nextSibling;e.appendChild(d);for(var i=g;i;i=g)g=i.nextSibling,e.appendChild(i)}return d}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),d;(d=a.parentNode)&&d.nodeType===1;)a=d;c.push(a)}for(var x=/(?:^|\s)nocode(?:\s|$)/,m=/\r\n?|\n/,j=a.ownerDocument,k=j.createElement("li");a.firstChild;)k.appendChild(a.firstChild);for(var c=[k],i=0;i<c.length;++i)b(c[i]);d===(d|0)&&c[0].setAttribute("value",d);var r=j.createElement("ol"); +r.className="linenums";for(var d=Math.max(0,d-1|0)||0,i=0,n=c.length;i<n;++i)k=c[i],k.className="L"+(i+d)%10,k.firstChild||k.appendChild(j.createTextNode("\u00a0")),r.appendChild(k);a.appendChild(r)}function p(a,d){for(var g=d.length;--g>=0;){var b=d[g];F.hasOwnProperty(b)?E.console&&console.warn("cannot override language handler %s",b):F[b]=a}}function I(a,d){if(!a||!F.hasOwnProperty(a))a=/^\s*</.test(d)?"default-markup":"default-code";return F[a]}function K(a){var d=a.h;try{var g=S(a.c,a.i),b=g.a; +a.a=b;a.d=g.d;a.e=0;I(d,b)(a);var s=/\bMSIE\s(\d+)/.exec(navigator.userAgent),s=s&&+s[1]<=8,d=/\n/g,x=a.a,m=x.length,g=0,j=a.d,k=j.length,b=0,c=a.g,i=c.length,r=0;c[i]=m;var n,e;for(e=n=0;e<i;)c[e]!==c[e+2]?(c[n++]=c[e++],c[n++]=c[e++]):e+=2;i=n;for(e=n=0;e<i;){for(var p=c[e],w=c[e+1],t=e+2;t+2<=i&&c[t+1]===w;)t+=2;c[n++]=p;c[n++]=w;e=t}c.length=n;var f=a.c,h;if(f)h=f.style.display,f.style.display="none";try{for(;b<k;){var l=j[b+2]||m,B=c[r+2]||m,t=Math.min(l,B),A=j[b+1],G;if(A.nodeType!==1&&(G=x.substring(g, +t))){s&&(G=G.replace(d,"\r"));A.nodeValue=G;var L=A.ownerDocument,o=L.createElement("span");o.className=c[r+1];var v=A.parentNode;v.replaceChild(o,A);o.appendChild(A);g<l&&(j[b+1]=A=L.createTextNode(x.substring(t,l)),v.insertBefore(A,o.nextSibling))}g=t;g>=l&&(b+=2);g>=B&&(r+=2)}}finally{if(f)f.style.display=h}}catch(u){E.console&&console.log(u&&u.stack||u)}}var E=window,y=["break,continue,do,else,for,if,return,while"],C=[[y,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],M=[C,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],V=[C,"abstract,assert,boolean,byte,extends,final,finally,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"], +N=[C,"abstract,as,base,bool,by,byte,checked,decimal,delegate,descending,dynamic,event,finally,fixed,foreach,from,group,implicit,in,interface,internal,into,is,let,lock,null,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"],C=[C,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],O=[y,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], +P=[y,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],W=[y,"as,assert,const,copy,drop,enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,pub,pure,ref,self,static,struct,true,trait,type,unsafe,use"],y=[y,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],Q=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/, +U=/\S/,X=v({keywords:[M,N,C,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",O,P,y],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),F={};p(X,["default-code"]);p(D([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-", +/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i] ]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);p(D([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"] ],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/], +["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",/^style\s*=\s*([^\s"'>]+)/i] ]),["in.tag"]);p(D([],[["atv",/^[\S\s]+/] ]),["uq.val"]);p(v({keywords:M,hashComments:!0,cStyleComments:!0,types:Q}),["c","cc","cpp","cxx","cyc","m"]);p(v({keywords:"null,true,false"}),["json"]);p(v({keywords:N,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:Q}), +["cs"]);p(v({keywords:V,cStyleComments:!0}),["java"]);p(v({keywords:y,hashComments:!0,multiLineStrings:!0}),["bash","bsh","csh","sh"]);p(v({keywords:O,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),["cv","py","python"]);p(v({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:2}),["perl","pl","pm"]);p(v({keywords:P, +hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb","ruby"]);p(v({keywords:C,cStyleComments:!0,regexLiterals:!0}),["javascript","js"]);p(v({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes",hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);p(v({keywords:W,cStyleComments:!0,multilineStrings:!0}),["rc","rs","rust"]); +p(D([],[["str",/^[\S\s]+/] ]),["regex"]);var Y=E.PR={createSimpleLexer:D,registerLangHandler:p,sourceDecorator:v,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ",prettyPrintOne:E.prettyPrintOne=function(a,d,g){var b=document.createElement("div");b.innerHTML="<pre>"+a+"</pre>";b=b.firstChild;g&&J(b,g,!0);K({h:d,j:g,c:b,i:1}); +return b.innerHTML},prettyPrint:E.prettyPrint=function(a,d){function g(){for(var b=E.PR_SHOULD_USE_CONTINUATION?c.now()+250:Infinity;i<p.length&&c.now()<b;i++){for(var d=p[i],j=h,k=d;k=k.previousSibling;){var m=k.nodeType,o=(m===7||m===8)&&k.nodeValue;if(o?!/^\??prettify\b/.test(o):m!==3||/\S/.test(k.nodeValue))break;if(o){j={};o.replace(/\b(\w+)=([\w%+\-.:]+)/g,function(a,b,c){j[b]=c});break}}k=d.className;if((j!==h||e.test(k))&&!v.test(k)){m=!1;for(o=d.parentNode;o;o=o.parentNode)if(f.test(o.tagName)&& +o.className&&e.test(o.className)){m=!0;break}if(!m){d.className+=" prettyprinted";m=j.lang;if(!m){var m=k.match(n),y;if(!m&&(y=T(d))&&t.test(y.tagName))m=y.className.match(n);m&&(m=m[1])}if(w.test(d.tagName))o=1;else var o=d.currentStyle,u=s.defaultView,o=(o=o?o.whiteSpace:u&&u.getComputedStyle?u.getComputedStyle(d,q).getPropertyValue("white-space"):0)&&"pre"===o.substring(0,3);u=j.linenums;if(!(u=u==="true"||+u))u=(u=k.match(/\blinenums\b(?::(\d+))?/))?u[1]&&u[1].length?+u[1]:!0:!1;u&&J(d,u,o);r= +{h:m,c:d,j:u,i:o};K(r)}}}i<p.length?setTimeout(g,250):"function"===typeof a&&a()}for(var b=d||document.body,s=b.ownerDocument||document,b=[b.getElementsByTagName("pre"),b.getElementsByTagName("code"),b.getElementsByTagName("xmp")],p=[],m=0;m<b.length;++m)for(var j=0,k=b[m].length;j<k;++j)p.push(b[m][j]);var b=q,c=Date;c.now||(c={now:function(){return+new Date}});var i=0,r,n=/\blang(?:uage)?-([\w.]+)(?!\S)/,e=/\bprettyprint\b/,v=/\bprettyprinted\b/,w=/pre|xmp/i,t=/^code$/i,f=/^(?:pre|code|xmp)$/i, +h={};g()}};typeof define==="function"&&define.amd&&define("google-code-prettify",[],function(){return Y})})();}() +</script> +<style> +.pln{color:#1b181b}.str{color:#918b3b}.kwd{color:#7b59c0}.com{color:#9e8f9e}.typ{color:#516aec}.lit{color:#a65926}.clo,.opn,.pun{color:#1b181b}.tag{color:#ca402b}.atn{color:#a65926}.atv{color:#159393}.dec{color:#a65926}.var{color:#ca402b}.fun{color:#516aec}pre.prettyprint{background:#f7f3f7;color:#ab9bab;font-family:Menlo,Consolas,"Bitstream Vera Sans Mono","DejaVu Sans Mono",Monaco,monospace;font-size:12px;line-height:1.5;border:1px solid #d8cad8;padding:10px}ol.linenums{margin-top:0;margin-bottom:0} +body{min-width:200px;max-width:850px;margin:0 auto;padding:30px;}.chapter-nav{font-size: 10pt;}a:link,a:visited{color:#00f}.codeblock_name,code,pre.prettyprint{font-family:Monaco,"Lucida Console",monospace}body{font-size:14pt}.codeblock_name,.math,.seealso,code{font-size:10pt}.codeblock{page-break-inside:avoid;padding-bottom:15px}.math{text-indent:0}pre.prettyprint{font-size:10pt;padding:10px;border-radius:10px;border:none;white-space:pre-wrap}.codeblock_name{margin-top:1.25em;display:block}a:link{text-decoration:none}a:link:not(.lit):hover{color:#00f;text-decoration:underline}a:link:active{color:red}h4{padding-right:1.25em}h4.noheading{margin-bottom:0}h1{text-align:center}code{padding:2px}pre{-moz-tab-size:4;-o-tab-size:4;tab-size:4}p:not(.notp){margin:0;text-indent:2em}.two-col{list-style-type:none}.two-col li:before{content:'-';padding:5px;margin-right:5px;color:orange;background-color:#fff;display:inline-block}@media print{body{font-size:10pt}pre.prettyprint{font-size:8pt}.seealso{font-size:9pt}.codeblock_name,.math,code{font-size:8pt}.math{text-indent:0}} +/* code blocks (Style from jmeiners.com/lc3-vm, CC BY-NC-SA 4.0, used with attribution) */ + +/* Quotes and Block Quotes */ +blockquote { + margin: 1.5em 10px; + padding: 0.5em 10px; + border-left: 5px solid #ccc; + color: #666; + background-color: #f9f9f9; + font-style: italic; +} + +blockquote p { + margin: 0; + font-size: 1.2em; +} + +q { + quotes: "“" "”" "‘" "’"; + font-style: italic; +} + +q::before { + content: open-quote; +} + +q::after { + content: close-quote; +} + +/*! Color themes for Google Code Prettify | MIT License | github.com/jmblog/color-themes-for-google-code-prettify */ +.prettyprint { + background: #f5f7ff; + font-family: Menlo, "Bitstream Vera Sans Mono", "DejaVu Sans Mono", Monaco, Consolas, monospace; + border: 0 !important; +} + +.pln { + color: #202746; +} + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; + color: #202746; +} + +li.L0, +li.L1, +li.L2, +li.L3, +li.L4, +li.L5, +li.L6, +li.L7, +li.L8, +li.L9 { + padding-left: 1em; + background-color: #f5f7ff; + list-style-type: decimal; +} + +@media screen { + + /* string content */ + + .str { + color: #ac9739; + } + + /* keyword */ + + .kwd { + color: #6679cc; + } + + /* comment */ + + .com { + color: #202746; + } + + /* type name */ + + .typ { + color: #3d8fd1; + } + + /* literal value */ + + .lit { + color: #c76b29; + } + + /* punctuation */ + + .pun { + color: #202746; + } + + /* lisp open bracket */ + + .opn { + color: #202746; + } + + /* lisp close bracket */ + + .clo { + color: #202746; + } + + /* markup tag name */ + + .tag { + color: #c94922; + } + + /* markup attribute name */ + + .atn { + color: #c76b29; + } + + /* markup attribute value */ + + .atv { + color: #22a2c9; + } + + /* declaration */ + + .dec { + color: #c76b29; + } + + /* variable name */ + + .var { + color: #c94922; + } + + /* function name */ + + .fun { + color: #3d8fd1; + } +}</style> +</head> +<body onload="prettyPrint()"> +<section> +<h1>Parser</h1> +<a name="1:1"><div class="section"><h4>1. Note</h4></a> +<p>THIS IS A LITERATE PROGRAM! Go to <a href="https://reagancfischer.dev/projects/cminus/code/parser.lit">this link</a> to see the file that generated this HTML. +</p> + +</div> +<a name="1:2"><div class="section"><h4>2. The Parser</h4></a> +<p>The parser takes tokens from the lexer and builds an abstract syntax tree (AST) which we'll use to generate code. I'll be using a recursive descent parser for this project. +</p> +<p>This will be a "dumb" parser, meaning it won't do any semantic analysis or type checking. You can see this distinction in the code for parsing declarations, which just stores the tokens for the declaration in the type itself instead of building a type. +</p> +<p>A consequence of this is that the parser will freely accept nonsense like <code>double int x</code> or <code>int x = "hello";</code>, because both are valid according to the (simplified) grammar rules "vardecl -> type ID" and "vardecl -> type ID = expr". +</p> +<p>The parser also won't build a symbol table. That'll be done in the semantic analysis phase. +</p> + +</div> +<a name="1:3"><div class="section"><h4>3. Design</h4></a> +<p>I'll break the parser into several modules: +</p> +<ul> +<li>'ast.c' will contain functions for building the AST, with similar isolation to the lexer. +</li> +<li>'parsing.c' will contain functions for supporting the parser. If I define any functions that don't directly implement a grammar rule, they'll go here. +</li> +<li>'expression.c' will contain functions for parsing expressions. +</li> +<li>'declaration.c' will contain functions for parsing declarations. +</li> +<li>'statement.c' will contain functions for parsing statements. +</li> +</ul> + +</div> +<a name="1:4"><div class="section"><h4>4. The AST Interface</h4></a> +<p>The AST will be a tree of nodes, each representing a different part of the program. I'll define the AST in 'ast.h' and implement it in 'ast.c'. Like we did for tokens in the lexer, the AST will be an opaque type. The parser will only interact with the AST through functions I provide. +</p> +<p>We'll need functions for creating and destroying nodes and functions for getting the types and values of nodes. I'm going to make the AST immutable, meaning that once a node is created, it can't be changed. +</p> +<p>The AST will be implemented in 'ast.c'. All AST nodes share a common type, but extra data is stored using a zero-length array which resolves to a variable structure. +</p> +<p>All the code for this is about 1500 lines of mind-numbing code. See the full implementation <a href="https://reagancfischer.dev/projects/cminus/ast.html">here</a>. +</p> + +</div> +<a name="1:5"><div class="section"><h4>5. The Parser Interface</h4></a> +<h1> Source code, biblography</h1> +<p>A lot of the logic for this project is from either the Dragon Book, Engineering a Compiler, or LCC: A Retargetable Compiler for ANSI C. Grammars are from The C Reference Manual. +</p> +<p>Literate programming rendered using <a href="https://github.com/zyedidia/Literate">literate</a>. +</p> +<p> <footer style=" text-align: center; padding: 20px;"> + <p>© 2024 Reagan Fischer. If for some reason you want to use my AMAZING code (lol), it's available under the MIT + license <a href="/projects/cminus/code/LICENSE.md">here</a>.</p> + </footer> +</p> + +</div> +</body>